aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorPaul Stewart <pstew@chromium.org>2012-03-13 10:46:18 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-03-13 14:55:53 -0400
commit3117bbdb7899d43927c8ce4fe885ab7c1231c121 (patch)
treed2fc142e77a9d90d9054f45e666457c901bd8975 /net/mac80211/mlme.c
parente9ac0745c734d39cb55ce45f1fb03a85c972b35a (diff)
mac80211: Don't let regulatory make us deaf
When regulatory information changes our HT behavior (e.g, when we get a country code from the AP we have just associated with), we should use this information to change the power with which we transmit, and what channels we transmit. Sometimes the channel parameters we derive from regulatory information contradicts the parameters we used in association. For example, we could have associated specifying HT40, but the regulatory rules we apply may forbid HT40 operation. In the situation above, we should reconfigure ourselves to transmit in HT20 only, however it makes no sense for us to disable receive in HT40, since if we associated with these parameters, the AP has every reason to expect we can and will receive packets this way. The code in mac80211 does not have the capability of sending the appropriate action frames to signal a change in HT behaviour so the AP has no clue we can no longer receive frames encoded this way. In some broken AP implementations, this can leave us effectively deaf if the AP never retries in lower HT rates. This change breaks up the channel_type parameter in the ieee80211_enable_ht function into a separate receive and transmit part. It honors the channel flags set by regulatory in order to configure the rate control algorithm, but uses the capability flags to configure the channel on the radio, since these were used in association to set the AP's transmit rate. Signed-off-by: Paul Stewart <pstew@chromium.org> Cc: Sam Leffler <sleffler@chromium.org> Cc: Johannes Berg <johannes@sipsolutions.net> Reviewed-by: Luis R Rodriguez <mcgrof@frijolero.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c32
1 files changed, 16 insertions, 16 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 90d1db36cde..0df22372af8 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -189,7 +189,8 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
189 u16 ht_opmode; 189 u16 ht_opmode;
190 bool enable_ht = true; 190 bool enable_ht = true;
191 enum nl80211_channel_type prev_chantype; 191 enum nl80211_channel_type prev_chantype;
192 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; 192 enum nl80211_channel_type rx_channel_type = NL80211_CHAN_NO_HT;
193 enum nl80211_channel_type tx_channel_type;
193 194
194 sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 195 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
195 prev_chantype = sdata->vif.bss_conf.channel_type; 196 prev_chantype = sdata->vif.bss_conf.channel_type;
@@ -216,7 +217,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
216 } 217 }
217 218
218 if (enable_ht) { 219 if (enable_ht) {
219 channel_type = NL80211_CHAN_HT20; 220 rx_channel_type = NL80211_CHAN_HT20;
220 221
221 if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && 222 if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
222 !ieee80111_cfg_override_disables_ht40(sdata) && 223 !ieee80111_cfg_override_disables_ht40(sdata) &&
@@ -224,29 +225,28 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
224 (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { 225 (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
225 switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { 226 switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
226 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: 227 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
227 if (!(local->hw.conf.channel->flags & 228 rx_channel_type = NL80211_CHAN_HT40PLUS;
228 IEEE80211_CHAN_NO_HT40PLUS))
229 channel_type = NL80211_CHAN_HT40PLUS;
230 break; 229 break;
231 case IEEE80211_HT_PARAM_CHA_SEC_BELOW: 230 case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
232 if (!(local->hw.conf.channel->flags & 231 rx_channel_type = NL80211_CHAN_HT40MINUS;
233 IEEE80211_CHAN_NO_HT40MINUS))
234 channel_type = NL80211_CHAN_HT40MINUS;
235 break; 232 break;
236 } 233 }
237 } 234 }
238 } 235 }
239 236
237 tx_channel_type = ieee80211_get_tx_channel_type(local, rx_channel_type);
238
240 if (local->tmp_channel) 239 if (local->tmp_channel)
241 local->tmp_channel_type = channel_type; 240 local->tmp_channel_type = rx_channel_type;
242 241
243 if (!ieee80211_set_channel_type(local, sdata, channel_type)) { 242 if (!ieee80211_set_channel_type(local, sdata, rx_channel_type)) {
244 /* can only fail due to HT40+/- mismatch */ 243 /* can only fail due to HT40+/- mismatch */
245 channel_type = NL80211_CHAN_HT20; 244 rx_channel_type = NL80211_CHAN_HT20;
246 WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type)); 245 WARN_ON(!ieee80211_set_channel_type(local, sdata,
246 rx_channel_type));
247 } 247 }
248 248
249 if (beacon_htcap_ie && (prev_chantype != channel_type)) { 249 if (beacon_htcap_ie && (prev_chantype != rx_channel_type)) {
250 /* 250 /*
251 * Whenever the AP announces the HT mode change that can be 251 * Whenever the AP announces the HT mode change that can be
252 * 40MHz intolerant or etc., it would be safer to stop tx 252 * 40MHz intolerant or etc., it would be safer to stop tx
@@ -264,13 +264,13 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
264 /* channel_type change automatically detected */ 264 /* channel_type change automatically detected */
265 ieee80211_hw_config(local, 0); 265 ieee80211_hw_config(local, 0);
266 266
267 if (prev_chantype != channel_type) { 267 if (prev_chantype != tx_channel_type) {
268 rcu_read_lock(); 268 rcu_read_lock();
269 sta = sta_info_get(sdata, bssid); 269 sta = sta_info_get(sdata, bssid);
270 if (sta) 270 if (sta)
271 rate_control_rate_update(local, sband, sta, 271 rate_control_rate_update(local, sband, sta,
272 IEEE80211_RC_HT_CHANGED, 272 IEEE80211_RC_HT_CHANGED,
273 channel_type); 273 tx_channel_type);
274 rcu_read_unlock(); 274 rcu_read_unlock();
275 275
276 if (beacon_htcap_ie) 276 if (beacon_htcap_ie)
@@ -283,7 +283,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
283 /* if bss configuration changed store the new one */ 283 /* if bss configuration changed store the new one */
284 if (sdata->ht_opmode_valid != enable_ht || 284 if (sdata->ht_opmode_valid != enable_ht ||
285 sdata->vif.bss_conf.ht_operation_mode != ht_opmode || 285 sdata->vif.bss_conf.ht_operation_mode != ht_opmode ||
286 prev_chantype != channel_type) { 286 prev_chantype != rx_channel_type) {
287 changed |= BSS_CHANGED_HT; 287 changed |= BSS_CHANGED_HT;
288 sdata->vif.bss_conf.ht_operation_mode = ht_opmode; 288 sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
289 sdata->ht_opmode_valid = enable_ht; 289 sdata->ht_opmode_valid = enable_ht;