diff options
author | Stanislaw Gruszka <sgruszka@redhat.com> | 2011-06-08 09:26:31 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-06-08 14:19:05 -0400 |
commit | 51e65257142a87fe46a1ce5c35c86c5baf012614 (patch) | |
tree | e5210ffad470c6b7b9c969aac667d5d5b491f76c /drivers/net/wireless/iwlegacy/iwl4965-base.c | |
parent | f3209bea110cade12e2b133da8b8499689cb0e2e (diff) |
iwlegacy: fix channel switch locking
We use priv->mutex to avoid race conditions between chswitch_done()
and mac_channel_switch(), when marking channel switch in
progress. But chswitch_done() can be called in atomic context
from rx_csa() or with mutex already taken from commit_rxon().
To fix remove mutex from chswitch_done() and use atomic bitops
for marking channel switch pending.
Cc: stable@kernel.org # 2.6.39+
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlegacy/iwl4965-base.c')
-rw-r--r-- | drivers/net/wireless/iwlegacy/iwl4965-base.c | 20 |
1 files changed, 10 insertions, 10 deletions
diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index af2ae22fcfd3..7157ba529680 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c | |||
@@ -2861,16 +2861,13 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw, | |||
2861 | goto out; | 2861 | goto out; |
2862 | 2862 | ||
2863 | if (test_bit(STATUS_EXIT_PENDING, &priv->status) || | 2863 | if (test_bit(STATUS_EXIT_PENDING, &priv->status) || |
2864 | test_bit(STATUS_SCANNING, &priv->status)) | 2864 | test_bit(STATUS_SCANNING, &priv->status) || |
2865 | test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) | ||
2865 | goto out; | 2866 | goto out; |
2866 | 2867 | ||
2867 | if (!iwl_legacy_is_associated_ctx(ctx)) | 2868 | if (!iwl_legacy_is_associated_ctx(ctx)) |
2868 | goto out; | 2869 | goto out; |
2869 | 2870 | ||
2870 | /* channel switch in progress */ | ||
2871 | if (priv->switch_rxon.switch_in_progress == true) | ||
2872 | goto out; | ||
2873 | |||
2874 | if (priv->cfg->ops->lib->set_channel_switch) { | 2871 | if (priv->cfg->ops->lib->set_channel_switch) { |
2875 | 2872 | ||
2876 | ch = channel->hw_value; | 2873 | ch = channel->hw_value; |
@@ -2919,15 +2916,18 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw, | |||
2919 | * at this point, staging_rxon has the | 2916 | * at this point, staging_rxon has the |
2920 | * configuration for channel switch | 2917 | * configuration for channel switch |
2921 | */ | 2918 | */ |
2922 | if (priv->cfg->ops->lib->set_channel_switch(priv, | 2919 | set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status); |
2923 | ch_switch)) | 2920 | priv->switch_channel = cpu_to_le16(ch); |
2924 | priv->switch_rxon.switch_in_progress = false; | 2921 | if (priv->cfg->ops->lib->set_channel_switch(priv, ch_switch)) { |
2922 | clear_bit(STATUS_CHANNEL_SWITCH_PENDING, | ||
2923 | &priv->status); | ||
2924 | priv->switch_channel = 0; | ||
2925 | ieee80211_chswitch_done(ctx->vif, false); | ||
2926 | } | ||
2925 | } | 2927 | } |
2926 | } | 2928 | } |
2927 | out: | 2929 | out: |
2928 | mutex_unlock(&priv->mutex); | 2930 | mutex_unlock(&priv->mutex); |
2929 | if (!priv->switch_rxon.switch_in_progress) | ||
2930 | ieee80211_chswitch_done(ctx->vif, false); | ||
2931 | IWL_DEBUG_MAC80211(priv, "leave\n"); | 2931 | IWL_DEBUG_MAC80211(priv, "leave\n"); |
2932 | } | 2932 | } |
2933 | 2933 | ||