diff options
author | Shanyu Zhao <shanyu.zhao@intel.com> | 2010-07-28 16:40:39 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-08-24 16:32:01 -0400 |
commit | aa2dc6b529d781a375f7ad3185198f6315865b06 (patch) | |
tree | 86941fc4b57927321c2f8f96630aec4574b1212d | |
parent | 81e95430aaa898799421617c2db2882386bab69a (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.c | 14 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 14 |
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) |