aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/tdls.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/tdls.c')
-rw-r--r--net/mac80211/tdls.c155
1 files changed, 132 insertions, 23 deletions
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index c9f9752217ac..fff0d864adfa 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -136,6 +136,24 @@ ieee80211_tdls_add_supp_channels(struct ieee80211_sub_if_data *sdata,
136 *pos = 2 * subband_cnt; 136 *pos = 2 * subband_cnt;
137} 137}
138 138
139static void ieee80211_tdls_add_oper_classes(struct ieee80211_sub_if_data *sdata,
140 struct sk_buff *skb)
141{
142 u8 *pos;
143 u8 op_class;
144
145 if (!ieee80211_chandef_to_operating_class(&sdata->vif.bss_conf.chandef,
146 &op_class))
147 return;
148
149 pos = skb_put(skb, 4);
150 *pos++ = WLAN_EID_SUPPORTED_REGULATORY_CLASSES;
151 *pos++ = 2; /* len */
152
153 *pos++ = op_class;
154 *pos++ = op_class; /* give current operating class as alternate too */
155}
156
139static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb) 157static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb)
140{ 158{
141 u8 *pos = (void *)skb_put(skb, 3); 159 u8 *pos = (void *)skb_put(skb, 3);
@@ -193,6 +211,17 @@ static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata,
193 memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN); 211 memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN);
194} 212}
195 213
214static void
215ieee80211_tdls_add_aid(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
216{
217 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
218 u8 *pos = (void *)skb_put(skb, 4);
219
220 *pos++ = WLAN_EID_AID;
221 *pos++ = 2; /* len */
222 put_unaligned_le16(ifmgd->aid, pos);
223}
224
196/* translate numbering in the WMM parameter IE to the mac80211 notation */ 225/* translate numbering in the WMM parameter IE to the mac80211 notation */
197static enum ieee80211_ac_numbers ieee80211_ac_from_wmm(int ac) 226static enum ieee80211_ac_numbers ieee80211_ac_from_wmm(int ac)
198{ 227{
@@ -271,21 +300,11 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
271 struct ieee80211_local *local = sdata->local; 300 struct ieee80211_local *local = sdata->local;
272 struct ieee80211_supported_band *sband; 301 struct ieee80211_supported_band *sband;
273 struct ieee80211_sta_ht_cap ht_cap; 302 struct ieee80211_sta_ht_cap ht_cap;
303 struct ieee80211_sta_vht_cap vht_cap;
274 struct sta_info *sta = NULL; 304 struct sta_info *sta = NULL;
275 size_t offset = 0, noffset; 305 size_t offset = 0, noffset;
276 u8 *pos; 306 u8 *pos;
277 307
278 rcu_read_lock();
279
280 /* we should have the peer STA if we're already responding */
281 if (action_code == WLAN_TDLS_SETUP_RESPONSE) {
282 sta = sta_info_get(sdata, peer);
283 if (WARN_ON_ONCE(!sta)) {
284 rcu_read_unlock();
285 return;
286 }
287 }
288
289 ieee80211_add_srates_ie(sdata, skb, false, band); 308 ieee80211_add_srates_ie(sdata, skb, false, band);
290 ieee80211_add_ext_srates_ie(sdata, skb, false, band); 309 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
291 ieee80211_tdls_add_supp_channels(sdata, skb); 310 ieee80211_tdls_add_supp_channels(sdata, skb);
@@ -338,6 +357,19 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
338 offset = noffset; 357 offset = noffset;
339 } 358 }
340 359
360 rcu_read_lock();
361
362 /* we should have the peer STA if we're already responding */
363 if (action_code == WLAN_TDLS_SETUP_RESPONSE) {
364 sta = sta_info_get(sdata, peer);
365 if (WARN_ON_ONCE(!sta)) {
366 rcu_read_unlock();
367 return;
368 }
369 }
370
371 ieee80211_tdls_add_oper_classes(sdata, skb);
372
341 /* 373 /*
342 * with TDLS we can switch channels, and HT-caps are not necessarily 374 * with TDLS we can switch channels, and HT-caps are not necessarily
343 * the same on all bands. The specification limits the setup to a 375 * the same on all bands. The specification limits the setup to a
@@ -346,7 +378,9 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
346 sband = local->hw.wiphy->bands[band]; 378 sband = local->hw.wiphy->bands[band];
347 memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); 379 memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
348 380
349 if (action_code == WLAN_TDLS_SETUP_REQUEST && ht_cap.ht_supported) { 381 if ((action_code == WLAN_TDLS_SETUP_REQUEST ||
382 action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) &&
383 ht_cap.ht_supported) {
350 ieee80211_apply_htcap_overrides(sdata, &ht_cap); 384 ieee80211_apply_htcap_overrides(sdata, &ht_cap);
351 385
352 /* disable SMPS in TDLS initiator */ 386 /* disable SMPS in TDLS initiator */
@@ -368,12 +402,63 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
368 ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap); 402 ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap);
369 } 403 }
370 404
371 rcu_read_unlock();
372
373 if (ht_cap.ht_supported && 405 if (ht_cap.ht_supported &&
374 (ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) 406 (ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
375 ieee80211_tdls_add_bss_coex_ie(skb); 407 ieee80211_tdls_add_bss_coex_ie(skb);
376 408
409 ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
410
411 /* add any custom IEs that go before VHT capabilities */
412 if (extra_ies_len) {
413 static const u8 before_vht_cap[] = {
414 WLAN_EID_SUPP_RATES,
415 WLAN_EID_COUNTRY,
416 WLAN_EID_EXT_SUPP_RATES,
417 WLAN_EID_SUPPORTED_CHANNELS,
418 WLAN_EID_RSN,
419 WLAN_EID_EXT_CAPABILITY,
420 WLAN_EID_QOS_CAPA,
421 WLAN_EID_FAST_BSS_TRANSITION,
422 WLAN_EID_TIMEOUT_INTERVAL,
423 WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
424 WLAN_EID_MULTI_BAND,
425 };
426 noffset = ieee80211_ie_split(extra_ies, extra_ies_len,
427 before_vht_cap,
428 ARRAY_SIZE(before_vht_cap),
429 offset);
430 pos = skb_put(skb, noffset - offset);
431 memcpy(pos, extra_ies + offset, noffset - offset);
432 offset = noffset;
433 }
434
435 /* build the VHT-cap similarly to the HT-cap */
436 memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap));
437 if ((action_code == WLAN_TDLS_SETUP_REQUEST ||
438 action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) &&
439 vht_cap.vht_supported) {
440 ieee80211_apply_vhtcap_overrides(sdata, &vht_cap);
441
442 /* the AID is present only when VHT is implemented */
443 if (action_code == WLAN_TDLS_SETUP_REQUEST)
444 ieee80211_tdls_add_aid(sdata, skb);
445
446 pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
447 ieee80211_ie_build_vht_cap(pos, &vht_cap, vht_cap.cap);
448 } else if (action_code == WLAN_TDLS_SETUP_RESPONSE &&
449 vht_cap.vht_supported && sta->sta.vht_cap.vht_supported) {
450 /* the peer caps are already intersected with our own */
451 memcpy(&vht_cap, &sta->sta.vht_cap, sizeof(vht_cap));
452
453 /* the AID is present only when VHT is implemented */
454 ieee80211_tdls_add_aid(sdata, skb);
455
456 pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
457 ieee80211_ie_build_vht_cap(pos, &vht_cap, vht_cap.cap);
458 }
459
460 rcu_read_unlock();
461
377 /* add any remaining IEs */ 462 /* add any remaining IEs */
378 if (extra_ies_len) { 463 if (extra_ies_len) {
379 noffset = extra_ies_len; 464 noffset = extra_ies_len;
@@ -381,7 +466,6 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
381 memcpy(pos, extra_ies + offset, noffset - offset); 466 memcpy(pos, extra_ies + offset, noffset - offset);
382 } 467 }
383 468
384 ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
385} 469}
386 470
387static void 471static void
@@ -394,6 +478,7 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
394 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 478 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
395 size_t offset = 0, noffset; 479 size_t offset = 0, noffset;
396 struct sta_info *sta, *ap_sta; 480 struct sta_info *sta, *ap_sta;
481 enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
397 u8 *pos; 482 u8 *pos;
398 483
399 rcu_read_lock(); 484 rcu_read_lock();
@@ -453,6 +538,21 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
453 } 538 }
454 } 539 }
455 540
541 ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
542
543 /* only include VHT-operation if not on the 2.4GHz band */
544 if (band != IEEE80211_BAND_2GHZ && !ap_sta->sta.vht_cap.vht_supported &&
545 sta->sta.vht_cap.vht_supported) {
546 struct ieee80211_chanctx_conf *chanctx_conf =
547 rcu_dereference(sdata->vif.chanctx_conf);
548 if (!WARN_ON(!chanctx_conf)) {
549 pos = skb_put(skb, 2 +
550 sizeof(struct ieee80211_vht_operation));
551 ieee80211_ie_build_vht_oper(pos, &sta->sta.vht_cap,
552 &chanctx_conf->def);
553 }
554 }
555
456 rcu_read_unlock(); 556 rcu_read_unlock();
457 557
458 /* add any remaining IEs */ 558 /* add any remaining IEs */
@@ -461,8 +561,6 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
461 pos = skb_put(skb, noffset - offset); 561 pos = skb_put(skb, noffset - offset);
462 memcpy(pos, extra_ies + offset, noffset - offset); 562 memcpy(pos, extra_ies + offset, noffset - offset);
463 } 563 }
464
465 ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
466} 564}
467 565
468static void 566static void
@@ -708,8 +806,12 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata,
708 26 + /* max(WMM-info, WMM-param) */ 806 26 + /* max(WMM-info, WMM-param) */
709 2 + max(sizeof(struct ieee80211_ht_cap), 807 2 + max(sizeof(struct ieee80211_ht_cap),
710 sizeof(struct ieee80211_ht_operation)) + 808 sizeof(struct ieee80211_ht_operation)) +
809 2 + max(sizeof(struct ieee80211_vht_cap),
810 sizeof(struct ieee80211_vht_operation)) +
711 50 + /* supported channels */ 811 50 + /* supported channels */
712 3 + /* 40/20 BSS coex */ 812 3 + /* 40/20 BSS coex */
813 4 + /* AID */
814 4 + /* oper classes */
713 extra_ies_len + 815 extra_ies_len +
714 sizeof(struct ieee80211_tdls_lnkie)); 816 sizeof(struct ieee80211_tdls_lnkie));
715 if (!skb) 817 if (!skb)
@@ -907,7 +1009,7 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
907 if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer) && 1009 if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer) &&
908 !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) { 1010 !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) {
909 ret = -EBUSY; 1011 ret = -EBUSY;
910 goto exit; 1012 goto out_unlock;
911 } 1013 }
912 1014
913 /* 1015 /*
@@ -922,27 +1024,34 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
922 if (!sta_info_get(sdata, peer)) { 1024 if (!sta_info_get(sdata, peer)) {
923 rcu_read_unlock(); 1025 rcu_read_unlock();
924 ret = -ENOLINK; 1026 ret = -ENOLINK;
925 goto exit; 1027 goto out_unlock;
926 } 1028 }
927 rcu_read_unlock(); 1029 rcu_read_unlock();
928 } 1030 }
929 1031
930 ieee80211_flush_queues(local, sdata, false); 1032 ieee80211_flush_queues(local, sdata, false);
1033 memcpy(sdata->u.mgd.tdls_peer, peer, ETH_ALEN);
1034 mutex_unlock(&local->mtx);
931 1035
1036 /* we cannot take the mutex while preparing the setup packet */
932 ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, 1037 ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code,
933 dialog_token, status_code, 1038 dialog_token, status_code,
934 peer_capability, initiator, 1039 peer_capability, initiator,
935 extra_ies, extra_ies_len, 0, 1040 extra_ies, extra_ies_len, 0,
936 NULL); 1041 NULL);
937 if (ret < 0) 1042 if (ret < 0) {
938 goto exit; 1043 mutex_lock(&local->mtx);
1044 eth_zero_addr(sdata->u.mgd.tdls_peer);
1045 mutex_unlock(&local->mtx);
1046 return ret;
1047 }
939 1048
940 memcpy(sdata->u.mgd.tdls_peer, peer, ETH_ALEN);
941 ieee80211_queue_delayed_work(&sdata->local->hw, 1049 ieee80211_queue_delayed_work(&sdata->local->hw,
942 &sdata->u.mgd.tdls_peer_del_work, 1050 &sdata->u.mgd.tdls_peer_del_work,
943 TDLS_PEER_SETUP_TIMEOUT); 1051 TDLS_PEER_SETUP_TIMEOUT);
1052 return 0;
944 1053
945exit: 1054out_unlock:
946 mutex_unlock(&local->mtx); 1055 mutex_unlock(&local->mtx);
947 return ret; 1056 return ret;
948} 1057}