aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2010-05-05 09:28:27 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-05-07 14:55:51 -0400
commit0aaffa9b9699894aab3266195a529baf9f96ac29 (patch)
tree26fe5f5277ac6d7061ea723f92d4038b0c28b0b8 /net/mac80211/mlme.c
parentf444de05d20e27cdd960c13fcbcfca3099f03143 (diff)
mac80211: improve HT channel handling
Currently, when one interface switches HT mode, all others will follow along. This is clearly undesirable, since the new one might switch to no-HT while another one is operating in HT. Address this issue by keeping track of the HT mode per interface, and allowing only changes that are compatible, i.e. switching into HT40+ is not possible when another interface is in HT40-, in that case the second one needs to fall back to HT20. Also, to allow drivers to know what's going on, store the per-interface HT mode (channel type) in the virtual interface's bss_conf. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c44
1 files changed, 23 insertions, 21 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 17cb8ae912bc..6e149b49d4f0 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -136,11 +136,14 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
136 struct sta_info *sta; 136 struct sta_info *sta;
137 u32 changed = 0; 137 u32 changed = 0;
138 u16 ht_opmode; 138 u16 ht_opmode;
139 bool enable_ht = true, ht_changed; 139 bool enable_ht = true;
140 enum nl80211_channel_type prev_chantype;
140 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; 141 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
141 142
142 sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 143 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
143 144
145 prev_chantype = sdata->vif.bss_conf.channel_type;
146
144 /* HT is not supported */ 147 /* HT is not supported */
145 if (!sband->ht_cap.ht_supported) 148 if (!sband->ht_cap.ht_supported)
146 enable_ht = false; 149 enable_ht = false;
@@ -171,38 +174,37 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
171 } 174 }
172 } 175 }
173 176
174 ht_changed = conf_is_ht(&local->hw.conf) != enable_ht ||
175 channel_type != local->hw.conf.channel_type;
176
177 if (local->tmp_channel) 177 if (local->tmp_channel)
178 local->tmp_channel_type = channel_type; 178 local->tmp_channel_type = channel_type;
179 local->oper_channel_type = channel_type;
180 179
181 if (ht_changed) { 180 if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
182 /* channel_type change automatically detected */ 181 /* can only fail due to HT40+/- mismatch */
183 ieee80211_hw_config(local, 0); 182 channel_type = NL80211_CHAN_HT20;
183 WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type));
184 }
184 185
186 /* channel_type change automatically detected */
187 ieee80211_hw_config(local, 0);
188
189 if (prev_chantype != channel_type) {
185 rcu_read_lock(); 190 rcu_read_lock();
186 sta = sta_info_get(sdata, bssid); 191 sta = sta_info_get(sdata, bssid);
187 if (sta) 192 if (sta)
188 rate_control_rate_update(local, sband, sta, 193 rate_control_rate_update(local, sband, sta,
189 IEEE80211_RC_HT_CHANGED, 194 IEEE80211_RC_HT_CHANGED,
190 local->oper_channel_type); 195 channel_type);
191 rcu_read_unlock(); 196 rcu_read_unlock();
192 } 197 }
193
194 /* disable HT */
195 if (!enable_ht)
196 return 0;
197 198
198 ht_opmode = le16_to_cpu(hti->operation_mode); 199 ht_opmode = le16_to_cpu(hti->operation_mode);
199 200
200 /* if bss configuration changed store the new one */ 201 /* if bss configuration changed store the new one */
201 if (!sdata->ht_opmode_valid || 202 if (sdata->ht_opmode_valid != enable_ht ||
202 sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { 203 sdata->vif.bss_conf.ht_operation_mode != ht_opmode ||
204 prev_chantype != channel_type) {
203 changed |= BSS_CHANGED_HT; 205 changed |= BSS_CHANGED_HT;
204 sdata->vif.bss_conf.ht_operation_mode = ht_opmode; 206 sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
205 sdata->ht_opmode_valid = true; 207 sdata->ht_opmode_valid = enable_ht;
206 } 208 }
207 209
208 return changed; 210 return changed;
@@ -865,7 +867,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
865 ieee80211_set_wmm_default(sdata); 867 ieee80211_set_wmm_default(sdata);
866 868
867 /* channel(_type) changes are handled by ieee80211_hw_config */ 869 /* channel(_type) changes are handled by ieee80211_hw_config */
868 local->oper_channel_type = NL80211_CHAN_NO_HT; 870 WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
869 871
870 /* on the next assoc, re-program HT parameters */ 872 /* on the next assoc, re-program HT parameters */
871 sdata->ht_opmode_valid = false; 873 sdata->ht_opmode_valid = false;
@@ -882,8 +884,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
882 884
883 ieee80211_hw_config(local, config_changed); 885 ieee80211_hw_config(local, config_changed);
884 886
885 /* And the BSSID changed -- not very interesting here */ 887 /* The BSSID (not really interesting) and HT changed */
886 changed |= BSS_CHANGED_BSSID; 888 changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
887 ieee80211_bss_info_change_notify(sdata, changed); 889 ieee80211_bss_info_change_notify(sdata, changed);
888 890
889 if (remove_sta) 891 if (remove_sta)
@@ -2265,7 +2267,7 @@ int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
2265 if ((chan != local->tmp_channel || 2267 if ((chan != local->tmp_channel ||
2266 channel_type != local->tmp_channel_type) && 2268 channel_type != local->tmp_channel_type) &&
2267 (chan != local->oper_channel || 2269 (chan != local->oper_channel ||
2268 channel_type != local->oper_channel_type)) 2270 channel_type != local->_oper_channel_type))
2269 return -EBUSY; 2271 return -EBUSY;
2270 2272
2271 skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); 2273 skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);