diff options
-rw-r--r-- | net/mac80211/ieee80211_i.h | 4 | ||||
-rw-r--r-- | net/mac80211/main.c | 22 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 12 | ||||
-rw-r--r-- | net/mac80211/vht.c | 98 |
4 files changed, 135 insertions, 1 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 388580a1bada..8da53a067306 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -479,6 +479,8 @@ struct ieee80211_if_managed { | |||
479 | 479 | ||
480 | struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */ | 480 | struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */ |
481 | struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */ | 481 | struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */ |
482 | struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ | ||
483 | struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ | ||
482 | }; | 484 | }; |
483 | 485 | ||
484 | struct ieee80211_if_ibss { | 486 | struct ieee80211_if_ibss { |
@@ -1441,6 +1443,8 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta); | |||
1441 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | 1443 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, |
1442 | struct sta_info *sta, u8 opmode, | 1444 | struct sta_info *sta, u8 opmode, |
1443 | enum ieee80211_band band, bool nss_only); | 1445 | enum ieee80211_band band, bool nss_only); |
1446 | void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, | ||
1447 | struct ieee80211_sta_vht_cap *vht_cap); | ||
1444 | 1448 | ||
1445 | /* Spectrum management */ | 1449 | /* Spectrum management */ |
1446 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1450 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 1a8591b77a13..78554724f815 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -501,6 +501,27 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { | |||
501 | }, | 501 | }, |
502 | }; | 502 | }; |
503 | 503 | ||
504 | static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = { | ||
505 | .vht_cap_info = | ||
506 | cpu_to_le32(IEEE80211_VHT_CAP_RXLDPC | | ||
507 | IEEE80211_VHT_CAP_SHORT_GI_80 | | ||
508 | IEEE80211_VHT_CAP_SHORT_GI_160 | | ||
509 | IEEE80211_VHT_CAP_RXSTBC_1 | | ||
510 | IEEE80211_VHT_CAP_RXSTBC_2 | | ||
511 | IEEE80211_VHT_CAP_RXSTBC_3 | | ||
512 | IEEE80211_VHT_CAP_RXSTBC_4 | | ||
513 | IEEE80211_VHT_CAP_TXSTBC | | ||
514 | IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | | ||
515 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | | ||
516 | IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | | ||
517 | IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | | ||
518 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK), | ||
519 | .supp_mcs = { | ||
520 | .rx_mcs_map = cpu_to_le16(~0), | ||
521 | .tx_mcs_map = cpu_to_le16(~0), | ||
522 | }, | ||
523 | }; | ||
524 | |||
504 | static const u8 extended_capabilities[] = { | 525 | static const u8 extended_capabilities[] = { |
505 | 0, 0, 0, 0, 0, 0, 0, | 526 | 0, 0, 0, 0, 0, 0, 0, |
506 | WLAN_EXT_CAPA8_OPMODE_NOTIF, | 527 | WLAN_EXT_CAPA8_OPMODE_NOTIF, |
@@ -609,6 +630,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
609 | IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; | 630 | IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; |
610 | local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; | 631 | local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; |
611 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; | 632 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; |
633 | wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask; | ||
612 | 634 | ||
613 | INIT_LIST_HEAD(&local->interfaces); | 635 | INIT_LIST_HEAD(&local->interfaces); |
614 | 636 | ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 141577412d84..9784622cd3d1 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -609,6 +609,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | |||
609 | BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); | 609 | BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); |
610 | 610 | ||
611 | memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap)); | 611 | memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap)); |
612 | ieee80211_apply_vhtcap_overrides(sdata, &vht_cap); | ||
612 | 613 | ||
613 | /* determine capability flags */ | 614 | /* determine capability flags */ |
614 | cap = vht_cap.cap; | 615 | cap = vht_cap.cap; |
@@ -1802,9 +1803,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1802 | sdata->vif.bss_conf.p2p_ctwindow = 0; | 1803 | sdata->vif.bss_conf.p2p_ctwindow = 0; |
1803 | sdata->vif.bss_conf.p2p_oppps = false; | 1804 | sdata->vif.bss_conf.p2p_oppps = false; |
1804 | 1805 | ||
1805 | /* on the next assoc, re-program HT parameters */ | 1806 | /* on the next assoc, re-program HT/VHT parameters */ |
1806 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); | 1807 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); |
1807 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); | 1808 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); |
1809 | memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa)); | ||
1810 | memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask)); | ||
1808 | 1811 | ||
1809 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; | 1812 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; |
1810 | 1813 | ||
@@ -4071,6 +4074,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4071 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | 4074 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
4072 | } | 4075 | } |
4073 | 4076 | ||
4077 | if (req->flags & ASSOC_REQ_DISABLE_VHT) | ||
4078 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | ||
4079 | |||
4074 | /* Also disable HT if we don't support it or the AP doesn't use WMM */ | 4080 | /* Also disable HT if we don't support it or the AP doesn't use WMM */ |
4075 | sband = local->hw.wiphy->bands[req->bss->channel->band]; | 4081 | sband = local->hw.wiphy->bands[req->bss->channel->band]; |
4076 | if (!sband->ht_cap.ht_supported || | 4082 | if (!sband->ht_cap.ht_supported || |
@@ -4094,6 +4100,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4094 | memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, | 4100 | memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, |
4095 | sizeof(ifmgd->ht_capa_mask)); | 4101 | sizeof(ifmgd->ht_capa_mask)); |
4096 | 4102 | ||
4103 | memcpy(&ifmgd->vht_capa, &req->vht_capa, sizeof(ifmgd->vht_capa)); | ||
4104 | memcpy(&ifmgd->vht_capa_mask, &req->vht_capa_mask, | ||
4105 | sizeof(ifmgd->vht_capa_mask)); | ||
4106 | |||
4097 | if (req->ie && req->ie_len) { | 4107 | if (req->ie && req->ie_len) { |
4098 | memcpy(assoc_data->ie, req->ie, req->ie_len); | 4108 | memcpy(assoc_data->ie, req->ie, req->ie_len); |
4099 | assoc_data->ie_len = req->ie_len; | 4109 | assoc_data->ie_len = req->ie_len; |
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index a2c2258bc84e..cacc1c74556a 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -13,6 +13,104 @@ | |||
13 | #include "rate.h" | 13 | #include "rate.h" |
14 | 14 | ||
15 | 15 | ||
16 | static void __check_vhtcap_disable(struct ieee80211_sub_if_data *sdata, | ||
17 | struct ieee80211_sta_vht_cap *vht_cap, | ||
18 | u32 flag) | ||
19 | { | ||
20 | __le32 le_flag = cpu_to_le32(flag); | ||
21 | |||
22 | if (sdata->u.mgd.vht_capa_mask.vht_cap_info & le_flag && | ||
23 | !(sdata->u.mgd.vht_capa.vht_cap_info & le_flag)) | ||
24 | vht_cap->cap &= ~flag; | ||
25 | } | ||
26 | |||
27 | void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, | ||
28 | struct ieee80211_sta_vht_cap *vht_cap) | ||
29 | { | ||
30 | int i; | ||
31 | u16 rxmcs_mask, rxmcs_cap, rxmcs_n, txmcs_mask, txmcs_cap, txmcs_n; | ||
32 | |||
33 | if (!vht_cap->vht_supported) | ||
34 | return; | ||
35 | |||
36 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
37 | return; | ||
38 | |||
39 | __check_vhtcap_disable(sdata, vht_cap, | ||
40 | IEEE80211_VHT_CAP_RXLDPC); | ||
41 | __check_vhtcap_disable(sdata, vht_cap, | ||
42 | IEEE80211_VHT_CAP_SHORT_GI_80); | ||
43 | __check_vhtcap_disable(sdata, vht_cap, | ||
44 | IEEE80211_VHT_CAP_SHORT_GI_160); | ||
45 | __check_vhtcap_disable(sdata, vht_cap, | ||
46 | IEEE80211_VHT_CAP_TXSTBC); | ||
47 | __check_vhtcap_disable(sdata, vht_cap, | ||
48 | IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE); | ||
49 | __check_vhtcap_disable(sdata, vht_cap, | ||
50 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE); | ||
51 | __check_vhtcap_disable(sdata, vht_cap, | ||
52 | IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN); | ||
53 | __check_vhtcap_disable(sdata, vht_cap, | ||
54 | IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN); | ||
55 | |||
56 | /* Allow user to decrease AMPDU length exponent */ | ||
57 | if (sdata->u.mgd.vht_capa_mask.vht_cap_info & | ||
58 | cpu_to_le32(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK)) { | ||
59 | u32 cap, n; | ||
60 | |||
61 | n = le32_to_cpu(sdata->u.mgd.vht_capa.vht_cap_info) & | ||
62 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; | ||
63 | n >>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | ||
64 | cap = vht_cap->cap & IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; | ||
65 | cap >>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | ||
66 | |||
67 | if (n < cap) { | ||
68 | vht_cap->cap &= | ||
69 | ~IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; | ||
70 | vht_cap->cap |= | ||
71 | n << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | /* Allow the user to decrease MCSes */ | ||
76 | rxmcs_mask = | ||
77 | le16_to_cpu(sdata->u.mgd.vht_capa_mask.supp_mcs.rx_mcs_map); | ||
78 | rxmcs_n = le16_to_cpu(sdata->u.mgd.vht_capa.supp_mcs.rx_mcs_map); | ||
79 | rxmcs_n &= rxmcs_mask; | ||
80 | rxmcs_cap = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map); | ||
81 | |||
82 | txmcs_mask = | ||
83 | le16_to_cpu(sdata->u.mgd.vht_capa_mask.supp_mcs.tx_mcs_map); | ||
84 | txmcs_n = le16_to_cpu(sdata->u.mgd.vht_capa.supp_mcs.tx_mcs_map); | ||
85 | txmcs_n &= txmcs_mask; | ||
86 | txmcs_cap = le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map); | ||
87 | for (i = 0; i < 8; i++) { | ||
88 | u8 m, n, c; | ||
89 | |||
90 | m = (rxmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
91 | n = (rxmcs_n >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
92 | c = (rxmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
93 | |||
94 | if (m && ((c != IEEE80211_VHT_MCS_NOT_SUPPORTED && n < c) || | ||
95 | n == IEEE80211_VHT_MCS_NOT_SUPPORTED)) { | ||
96 | rxmcs_cap &= ~(3 << 2*i); | ||
97 | rxmcs_cap |= (rxmcs_n & (3 << 2*i)); | ||
98 | } | ||
99 | |||
100 | m = (txmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
101 | n = (txmcs_n >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
102 | c = (txmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
103 | |||
104 | if (m && ((c != IEEE80211_VHT_MCS_NOT_SUPPORTED && n < c) || | ||
105 | n == IEEE80211_VHT_MCS_NOT_SUPPORTED)) { | ||
106 | txmcs_cap &= ~(3 << 2*i); | ||
107 | txmcs_cap |= (txmcs_n & (3 << 2*i)); | ||
108 | } | ||
109 | } | ||
110 | vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(rxmcs_cap); | ||
111 | vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(txmcs_cap); | ||
112 | } | ||
113 | |||
16 | void | 114 | void |
17 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | 115 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, |
18 | struct ieee80211_supported_band *sband, | 116 | struct ieee80211_supported_band *sband, |