aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShanyu Zhao <shanyu.zhao@intel.com>2010-07-28 16:40:39 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-08-24 16:32:01 -0400
commitaa2dc6b529d781a375f7ad3185198f6315865b06 (patch)
tree86941fc4b57927321c2f8f96630aec4574b1212d
parent81e95430aaa898799421617c2db2882386bab69a (diff)
iwlwifi: avoid race condition in channel change
When iwl_mac_config() is called by mac80211, the channel pointer hw->conf->channel can potentially change, resulting in mismatch band and channel number when configuring RXON command. To avoid this situation, save the channel pointer in local variables and validate the channel before using it. Note that priv->mutex is locked during the whole function so the local variables are safe. Same change is applied to iwl_mac_channel_switch() since basically it copies code from iwl_mac_config(). Also removed an outdated comment in the flow. Signed-off-by: Shanyu Zhao <shanyu.zhao@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c14
2 files changed, 12 insertions, 16 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index eecfec7c4063..61ecd180982e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -3632,6 +3632,7 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
3632 struct iwl_priv *priv = hw->priv; 3632 struct iwl_priv *priv = hw->priv;
3633 const struct iwl_channel_info *ch_info; 3633 const struct iwl_channel_info *ch_info;
3634 struct ieee80211_conf *conf = &hw->conf; 3634 struct ieee80211_conf *conf = &hw->conf;
3635 struct ieee80211_channel *channel = ch_switch->channel;
3635 struct iwl_ht_config *ht_conf = &priv->current_ht_config; 3636 struct iwl_ht_config *ht_conf = &priv->current_ht_config;
3636 u16 ch; 3637 u16 ch;
3637 unsigned long flags = 0; 3638 unsigned long flags = 0;
@@ -3655,10 +3656,10 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
3655 mutex_lock(&priv->mutex); 3656 mutex_lock(&priv->mutex);
3656 if (priv->cfg->ops->lib->set_channel_switch) { 3657 if (priv->cfg->ops->lib->set_channel_switch) {
3657 3658
3658 ch = ch_switch->channel->hw_value; 3659 ch = channel->hw_value;
3659 if (le16_to_cpu(priv->active_rxon.channel) != ch) { 3660 if (le16_to_cpu(priv->active_rxon.channel) != ch) {
3660 ch_info = iwl_get_channel_info(priv, 3661 ch_info = iwl_get_channel_info(priv,
3661 conf->channel->band, 3662 channel->band,
3662 ch); 3663 ch);
3663 if (!is_channel_valid(ch_info)) { 3664 if (!is_channel_valid(ch_info)) {
3664 IWL_DEBUG_MAC80211(priv, "invalid channel\n"); 3665 IWL_DEBUG_MAC80211(priv, "invalid channel\n");
@@ -3687,15 +3688,12 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
3687 } else 3688 } else
3688 ht_conf->is_40mhz = false; 3689 ht_conf->is_40mhz = false;
3689 3690
3690 /* if we are switching from ht to 2.4 clear flags 3691 if (le16_to_cpu(priv->staging_rxon.channel) != ch)
3691 * from any ht related info since 2.4 does not
3692 * support ht */
3693 if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
3694 priv->staging_rxon.flags = 0; 3692 priv->staging_rxon.flags = 0;
3695 3693
3696 iwl_set_rxon_channel(priv, conf->channel); 3694 iwl_set_rxon_channel(priv, channel);
3697 iwl_set_rxon_ht(priv, ht_conf); 3695 iwl_set_rxon_ht(priv, ht_conf);
3698 iwl_set_flags_for_band(priv, conf->channel->band, 3696 iwl_set_flags_for_band(priv, channel->band,
3699 priv->vif); 3697 priv->vif);
3700 spin_unlock_irqrestore(&priv->lock, flags); 3698 spin_unlock_irqrestore(&priv->lock, flags);
3701 3699
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index dc29844cce1f..39aea7545603 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -1992,6 +1992,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
1992 struct iwl_priv *priv = hw->priv; 1992 struct iwl_priv *priv = hw->priv;
1993 const struct iwl_channel_info *ch_info; 1993 const struct iwl_channel_info *ch_info;
1994 struct ieee80211_conf *conf = &hw->conf; 1994 struct ieee80211_conf *conf = &hw->conf;
1995 struct ieee80211_channel *channel = conf->channel;
1995 struct iwl_ht_config *ht_conf = &priv->current_ht_config; 1996 struct iwl_ht_config *ht_conf = &priv->current_ht_config;
1996 unsigned long flags = 0; 1997 unsigned long flags = 0;
1997 int ret = 0; 1998 int ret = 0;
@@ -2001,7 +2002,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
2001 mutex_lock(&priv->mutex); 2002 mutex_lock(&priv->mutex);
2002 2003
2003 IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", 2004 IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n",
2004 conf->channel->hw_value, changed); 2005 channel->hw_value, changed);
2005 2006
2006 if (unlikely(!priv->cfg->mod_params->disable_hw_scan && 2007 if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
2007 test_bit(STATUS_SCANNING, &priv->status))) { 2008 test_bit(STATUS_SCANNING, &priv->status))) {
@@ -2032,8 +2033,8 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
2032 if (scan_active) 2033 if (scan_active)
2033 goto set_ch_out; 2034 goto set_ch_out;
2034 2035
2035 ch = conf->channel->hw_value; 2036 ch = channel->hw_value;
2036 ch_info = iwl_get_channel_info(priv, conf->channel->band, ch); 2037 ch_info = iwl_get_channel_info(priv, channel->band, ch);
2037 if (!is_channel_valid(ch_info)) { 2038 if (!is_channel_valid(ch_info)) {
2038 IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); 2039 IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
2039 ret = -EINVAL; 2040 ret = -EINVAL;
@@ -2064,16 +2065,13 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
2064 * from BSS config in iwl_ht_conf */ 2065 * from BSS config in iwl_ht_conf */
2065 ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE; 2066 ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
2066 2067
2067 /* if we are switching from ht to 2.4 clear flags
2068 * from any ht related info since 2.4 does not
2069 * support ht */
2070 if ((le16_to_cpu(priv->staging_rxon.channel) != ch)) 2068 if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
2071 priv->staging_rxon.flags = 0; 2069 priv->staging_rxon.flags = 0;
2072 2070
2073 iwl_set_rxon_channel(priv, conf->channel); 2071 iwl_set_rxon_channel(priv, channel);
2074 iwl_set_rxon_ht(priv, ht_conf); 2072 iwl_set_rxon_ht(priv, ht_conf);
2075 2073
2076 iwl_set_flags_for_band(priv, conf->channel->band, priv->vif); 2074 iwl_set_flags_for_band(priv, channel->band, priv->vif);
2077 spin_unlock_irqrestore(&priv->lock, flags); 2075 spin_unlock_irqrestore(&priv->lock, flags);
2078 2076
2079 if (priv->cfg->ops->lib->update_bcast_station) 2077 if (priv->cfg->ops->lib->update_bcast_station)