diff options
author | Arik Nemtsov <arik@wizery.com> | 2014-07-17 10:14:26 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2014-07-21 06:14:04 -0400 |
commit | 13cc8a4a1d24ff1f3b8b6de16779ef925371b18b (patch) | |
tree | 7589ca3656bbc6706d5dda61449a139ea7b212fb | |
parent | 81dd2b8822410e56048b927be779d95a2b6dc186 (diff) |
mac80211: support HT for TDLS stations
Add the HT capabilities and HT operation information elements to TDLS
setup packets where appropriate.
Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | net/mac80211/ht.c | 7 | ||||
-rw-r--r-- | net/mac80211/tdls.c | 88 |
2 files changed, 87 insertions, 8 deletions
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 15702ff64a4c..568055c02a98 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -150,13 +150,12 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
150 | 150 | ||
151 | /* | 151 | /* |
152 | * If user has specified capability over-rides, take care | 152 | * If user has specified capability over-rides, take care |
153 | * of that if the station we're setting up is the AP that | 153 | * of that if the station we're setting up is the AP or TDLS peer that |
154 | * we advertised a restricted capability set to. Override | 154 | * we advertised a restricted capability set to. Override |
155 | * our own capabilities and then use those below. | 155 | * our own capabilities and then use those below. |
156 | */ | 156 | */ |
157 | if ((sdata->vif.type == NL80211_IFTYPE_STATION || | 157 | if (sdata->vif.type == NL80211_IFTYPE_STATION || |
158 | sdata->vif.type == NL80211_IFTYPE_ADHOC) && | 158 | sdata->vif.type == NL80211_IFTYPE_ADHOC) |
159 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
160 | ieee80211_apply_htcap_overrides(sdata, &own_cap); | 159 | ieee80211_apply_htcap_overrides(sdata, &own_cap); |
161 | 160 | ||
162 | /* | 161 | /* |
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index c59b8f460eb9..50d0e0660cc4 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c | |||
@@ -170,9 +170,23 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
170 | { | 170 | { |
171 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | 171 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); |
172 | struct ieee80211_local *local = sdata->local; | 172 | struct ieee80211_local *local = sdata->local; |
173 | struct ieee80211_supported_band *sband; | ||
174 | struct ieee80211_sta_ht_cap ht_cap; | ||
175 | struct sta_info *sta = NULL; | ||
173 | size_t offset = 0, noffset; | 176 | size_t offset = 0, noffset; |
174 | u8 *pos; | 177 | u8 *pos; |
175 | 178 | ||
179 | rcu_read_lock(); | ||
180 | |||
181 | /* we should have the peer STA if we're already responding */ | ||
182 | if (action_code == WLAN_TDLS_SETUP_RESPONSE) { | ||
183 | sta = sta_info_get(sdata, peer); | ||
184 | if (WARN_ON_ONCE(!sta)) { | ||
185 | rcu_read_unlock(); | ||
186 | return; | ||
187 | } | ||
188 | } | ||
189 | |||
176 | ieee80211_add_srates_ie(sdata, skb, false, band); | 190 | ieee80211_add_srates_ie(sdata, skb, false, band); |
177 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); | 191 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); |
178 | 192 | ||
@@ -224,6 +238,38 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
224 | offset = noffset; | 238 | offset = noffset; |
225 | } | 239 | } |
226 | 240 | ||
241 | /* | ||
242 | * with TDLS we can switch channels, and HT-caps are not necessarily | ||
243 | * the same on all bands. The specification limits the setup to a | ||
244 | * single HT-cap, so use the current band for now. | ||
245 | */ | ||
246 | sband = local->hw.wiphy->bands[band]; | ||
247 | memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); | ||
248 | if ((action_code == WLAN_TDLS_SETUP_REQUEST || | ||
249 | action_code == WLAN_TDLS_SETUP_RESPONSE) && | ||
250 | ht_cap.ht_supported && (!sta || sta->sta.ht_cap.ht_supported)) { | ||
251 | if (action_code == WLAN_TDLS_SETUP_REQUEST) { | ||
252 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); | ||
253 | |||
254 | /* disable SMPS in TDLS initiator */ | ||
255 | ht_cap.cap |= (WLAN_HT_CAP_SM_PS_DISABLED | ||
256 | << IEEE80211_HT_CAP_SM_PS_SHIFT); | ||
257 | } else { | ||
258 | /* disable SMPS in TDLS responder */ | ||
259 | sta->sta.ht_cap.cap |= | ||
260 | (WLAN_HT_CAP_SM_PS_DISABLED | ||
261 | << IEEE80211_HT_CAP_SM_PS_SHIFT); | ||
262 | |||
263 | /* the peer caps are already intersected with our own */ | ||
264 | memcpy(&ht_cap, &sta->sta.ht_cap, sizeof(ht_cap)); | ||
265 | } | ||
266 | |||
267 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); | ||
268 | ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap); | ||
269 | } | ||
270 | |||
271 | rcu_read_unlock(); | ||
272 | |||
227 | /* add any remaining IEs */ | 273 | /* add any remaining IEs */ |
228 | if (extra_ies_len) { | 274 | if (extra_ies_len) { |
229 | noffset = extra_ies_len; | 275 | noffset = extra_ies_len; |
@@ -241,14 +287,16 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, | |||
241 | size_t extra_ies_len) | 287 | size_t extra_ies_len) |
242 | { | 288 | { |
243 | struct ieee80211_local *local = sdata->local; | 289 | struct ieee80211_local *local = sdata->local; |
290 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
244 | size_t offset = 0, noffset; | 291 | size_t offset = 0, noffset; |
245 | struct sta_info *sta; | 292 | struct sta_info *sta, *ap_sta; |
246 | u8 *pos; | 293 | u8 *pos; |
247 | 294 | ||
248 | rcu_read_lock(); | 295 | rcu_read_lock(); |
249 | 296 | ||
250 | sta = sta_info_get(sdata, peer); | 297 | sta = sta_info_get(sdata, peer); |
251 | if (WARN_ON_ONCE(!sta)) { | 298 | ap_sta = sta_info_get(sdata, ifmgd->bssid); |
299 | if (WARN_ON_ONCE(!sta || !ap_sta)) { | ||
252 | rcu_read_unlock(); | 300 | rcu_read_unlock(); |
253 | return; | 301 | return; |
254 | } | 302 | } |
@@ -272,6 +320,38 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, | |||
272 | test_sta_flag(sta, WLAN_STA_WME)) | 320 | test_sta_flag(sta, WLAN_STA_WME)) |
273 | ieee80211_tdls_add_wmm_param_ie(sdata, skb); | 321 | ieee80211_tdls_add_wmm_param_ie(sdata, skb); |
274 | 322 | ||
323 | /* add any custom IEs that go before HT operation */ | ||
324 | if (extra_ies_len) { | ||
325 | static const u8 before_ht_op[] = { | ||
326 | WLAN_EID_RSN, | ||
327 | WLAN_EID_QOS_CAPA, | ||
328 | WLAN_EID_FAST_BSS_TRANSITION, | ||
329 | WLAN_EID_TIMEOUT_INTERVAL, | ||
330 | }; | ||
331 | noffset = ieee80211_ie_split(extra_ies, extra_ies_len, | ||
332 | before_ht_op, | ||
333 | ARRAY_SIZE(before_ht_op), | ||
334 | offset); | ||
335 | pos = skb_put(skb, noffset - offset); | ||
336 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
337 | offset = noffset; | ||
338 | } | ||
339 | |||
340 | /* if HT support is only added in TDLS, we need an HT-operation IE */ | ||
341 | if (!ap_sta->sta.ht_cap.ht_supported && sta->sta.ht_cap.ht_supported) { | ||
342 | struct ieee80211_chanctx_conf *chanctx_conf = | ||
343 | rcu_dereference(sdata->vif.chanctx_conf); | ||
344 | if (!WARN_ON(!chanctx_conf)) { | ||
345 | pos = skb_put(skb, 2 + | ||
346 | sizeof(struct ieee80211_ht_operation)); | ||
347 | /* send an empty HT operation IE */ | ||
348 | ieee80211_ie_build_ht_oper(pos, &sta->sta.ht_cap, | ||
349 | &chanctx_conf->def, 0); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | rcu_read_unlock(); | ||
354 | |||
275 | /* add any remaining IEs */ | 355 | /* add any remaining IEs */ |
276 | if (extra_ies_len) { | 356 | if (extra_ies_len) { |
277 | noffset = extra_ies_len; | 357 | noffset = extra_ies_len; |
@@ -280,8 +360,6 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, | |||
280 | } | 360 | } |
281 | 361 | ||
282 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | 362 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); |
283 | |||
284 | rcu_read_unlock(); | ||
285 | } | 363 | } |
286 | 364 | ||
287 | static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, | 365 | static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, |
@@ -441,6 +519,8 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
441 | 50 + /* supported rates */ | 519 | 50 + /* supported rates */ |
442 | 7 + /* ext capab */ | 520 | 7 + /* ext capab */ |
443 | 26 + /* max(WMM-info, WMM-param) */ | 521 | 26 + /* max(WMM-info, WMM-param) */ |
522 | 2 + max(sizeof(struct ieee80211_ht_cap), | ||
523 | sizeof(struct ieee80211_ht_operation)) + | ||
444 | extra_ies_len + | 524 | extra_ies_len + |
445 | sizeof(struct ieee80211_tdls_lnkie)); | 525 | sizeof(struct ieee80211_tdls_lnkie)); |
446 | if (!skb) | 526 | if (!skb) |