aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>2010-06-09 06:43:26 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-06-14 15:42:31 -0400
commit685429623f88d84f98bd5daffc3c427c408740d4 (patch)
treed50f119094dd3fb7668f837dbe50857d11bb4fa3 /net/mac80211/mlme.c
parent5ea096c0c85e80335889539899af9a4717976e0b (diff)
mac80211: Fix circular locking dependency in ARP filter handling
There is a circular locking dependency when configuring the hardware ARP filters on association, occurring when flushing the mac80211 workqueue. This is what happens: [ 92.026800] ======================================================= [ 92.030507] [ INFO: possible circular locking dependency detected ] [ 92.030507] 2.6.34-04781-g2b2c009 #85 [ 92.030507] ------------------------------------------------------- [ 92.030507] modprobe/5225 is trying to acquire lock: [ 92.030507] ((wiphy_name(local->hw.wiphy))){+.+.+.}, at: [<ffffffff8105b5c0>] flush_workq ueue+0x0/0xb0 [ 92.030507] [ 92.030507] but task is already holding lock: [ 92.030507] (rtnl_mutex){+.+.+.}, at: [<ffffffff812b9ce2>] rtnl_lock+0x12/0x20 [ 92.030507] [ 92.030507] which lock already depends on the new lock. [ 92.030507] [ 92.030507] [ 92.030507] the existing dependency chain (in reverse order) is: [ 92.030507] [ 92.030507] -> #2 (rtnl_mutex){+.+.+.}: [ 92.030507] [<ffffffff810761fb>] lock_acquire+0xdb/0x110 [ 92.030507] [<ffffffff81341754>] mutex_lock_nested+0x44/0x300 [ 92.030507] [<ffffffff812b9ce2>] rtnl_lock+0x12/0x20 [ 92.030507] [<ffffffffa022d47c>] ieee80211_assoc_done+0x6c/0xe0 [mac80211] [ 92.030507] [<ffffffffa022f2ad>] ieee80211_work_work+0x31d/0x1280 [mac80211] [ 92.030507] -> #1 ((&local->work_work)){+.+.+.}: [ 92.030507] [<ffffffff810761fb>] lock_acquire+0xdb/0x110 [ 92.030507] [<ffffffff8105a51a>] worker_thread+0x22a/0x370 [ 92.030507] [<ffffffff8105ecc6>] kthread+0x96/0xb0 [ 92.030507] [<ffffffff81003a94>] kernel_thread_helper+0x4/0x10 [ 92.030507] [ 92.030507] -> #0 ((wiphy_name(local->hw.wiphy))){+.+.+.}: [ 92.030507] [<ffffffff81075fdc>] __lock_acquire+0x1c0c/0x1d50 [ 92.030507] [<ffffffff810761fb>] lock_acquire+0xdb/0x110 [ 92.030507] [<ffffffff8105b60e>] flush_workqueue+0x4e/0xb0 [ 92.030507] [<ffffffffa023ff7b>] ieee80211_stop_device+0x2b/0xb0 [mac80211] [ 92.030507] [<ffffffffa0231635>] ieee80211_stop+0x3e5/0x680 [mac80211] The locking in this case is quite complex. Fix the problem by rewriting the way the hardware ARP filter list is handled - i.e. make a copy of the address list to the bss_conf struct, and provide that list to the hardware driver when needed. The current patch will enable filtering also in promiscuous mode. This may need to be changed in the future. Reported-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c34
1 files changed, 19 insertions, 15 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 583b34686a26..74479c2d12d4 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -806,11 +806,12 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
806{ 806{
807 struct ieee80211_bss *bss = (void *)cbss->priv; 807 struct ieee80211_bss *bss = (void *)cbss->priv;
808 struct ieee80211_local *local = sdata->local; 808 struct ieee80211_local *local = sdata->local;
809 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
809 810
810 bss_info_changed |= BSS_CHANGED_ASSOC; 811 bss_info_changed |= BSS_CHANGED_ASSOC;
811 /* set timing information */ 812 /* set timing information */
812 sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; 813 bss_conf->beacon_int = cbss->beacon_interval;
813 sdata->vif.bss_conf.timestamp = cbss->tsf; 814 bss_conf->timestamp = cbss->tsf;
814 815
815 bss_info_changed |= BSS_CHANGED_BEACON_INT; 816 bss_info_changed |= BSS_CHANGED_BEACON_INT;
816 bss_info_changed |= ieee80211_handle_bss_capability(sdata, 817 bss_info_changed |= ieee80211_handle_bss_capability(sdata,
@@ -835,7 +836,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
835 836
836 ieee80211_led_assoc(local, 1); 837 ieee80211_led_assoc(local, 1);
837 838
838 sdata->vif.bss_conf.assoc = 1; 839 bss_conf->assoc = 1;
839 /* 840 /*
840 * For now just always ask the driver to update the basic rateset 841 * For now just always ask the driver to update the basic rateset
841 * when we have associated, we aren't checking whether it actually 842 * when we have associated, we aren't checking whether it actually
@@ -848,9 +849,15 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
848 849
849 /* Tell the driver to monitor connection quality (if supported) */ 850 /* Tell the driver to monitor connection quality (if supported) */
850 if ((local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) && 851 if ((local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) &&
851 sdata->vif.bss_conf.cqm_rssi_thold) 852 bss_conf->cqm_rssi_thold)
852 bss_info_changed |= BSS_CHANGED_CQM; 853 bss_info_changed |= BSS_CHANGED_CQM;
853 854
855 /* Enable ARP filtering */
856 if (bss_conf->arp_filter_enabled != sdata->arp_filter_state) {
857 bss_conf->arp_filter_enabled = sdata->arp_filter_state;
858 bss_info_changed |= BSS_CHANGED_ARP_FILTER;
859 }
860
854 ieee80211_bss_info_change_notify(sdata, bss_info_changed); 861 ieee80211_bss_info_change_notify(sdata, bss_info_changed);
855 862
856 mutex_lock(&local->iflist_mtx); 863 mutex_lock(&local->iflist_mtx);
@@ -932,6 +939,12 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
932 939
933 ieee80211_hw_config(local, config_changed); 940 ieee80211_hw_config(local, config_changed);
934 941
942 /* Disable ARP filtering */
943 if (sdata->vif.bss_conf.arp_filter_enabled) {
944 sdata->vif.bss_conf.arp_filter_enabled = false;
945 changed |= BSS_CHANGED_ARP_FILTER;
946 }
947
935 /* The BSSID (not really interesting) and HT changed */ 948 /* The BSSID (not really interesting) and HT changed */
936 changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; 949 changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
937 ieee80211_bss_info_change_notify(sdata, changed); 950 ieee80211_bss_info_change_notify(sdata, changed);
@@ -2018,18 +2031,9 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
2018 cfg80211_send_assoc_timeout(wk->sdata->dev, 2031 cfg80211_send_assoc_timeout(wk->sdata->dev,
2019 wk->filter_ta); 2032 wk->filter_ta);
2020 return WORK_DONE_DESTROY; 2033 return WORK_DONE_DESTROY;
2021 } else {
2022 mutex_unlock(&wk->sdata->u.mgd.mtx);
2023#ifdef CONFIG_INET
2024 /*
2025 * configure ARP filter IP addresses to the driver,
2026 * intentionally outside the mgd mutex.
2027 */
2028 rtnl_lock();
2029 ieee80211_set_arp_filter(wk->sdata);
2030 rtnl_unlock();
2031#endif
2032 } 2034 }
2035
2036 mutex_unlock(&wk->sdata->u.mgd.mtx);
2033 } 2037 }
2034 2038
2035 cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); 2039 cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len);