summaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorLuca Coelho <luciano.coelho@intel.com>2018-06-09 02:14:44 -0400
committerJohannes Berg <johannes.berg@intel.com>2018-06-18 16:40:32 -0400
commit41cbb0f5a29592874355e4159489eb08337cd50e (patch)
treeee56f9b9754452ae89a6f9b89efc63d2c360a50a /net/mac80211/mlme.c
parentb8042b3da925f390c1482bf9dc0898dc0b3ea7b5 (diff)
mac80211: add support for HE
Add support for HE in mac80211 conforming with P802.11ax_D1.4. Johannes: Fix another bug with the buf_size comparison in agg-rx.c. Signed-off-by: Liad Kaufman <liad.kaufman@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Ilan Peer <ilan.peer@intel.com> Signed-off-by: Ido Yariv <idox.yariv@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c288
1 files changed, 271 insertions, 17 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index a44e5b4aaeda..0322d78007ad 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -149,6 +149,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
149 struct ieee80211_channel *channel, 149 struct ieee80211_channel *channel,
150 const struct ieee80211_ht_operation *ht_oper, 150 const struct ieee80211_ht_operation *ht_oper,
151 const struct ieee80211_vht_operation *vht_oper, 151 const struct ieee80211_vht_operation *vht_oper,
152 const struct ieee80211_he_operation *he_oper,
152 struct cfg80211_chan_def *chandef, bool tracking) 153 struct cfg80211_chan_def *chandef, bool tracking)
153{ 154{
154 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 155 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -207,7 +208,27 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
207 } 208 }
208 209
209 vht_chandef = *chandef; 210 vht_chandef = *chandef;
210 if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) { 211 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && he_oper &&
212 (le32_to_cpu(he_oper->he_oper_params) &
213 IEEE80211_HE_OPERATION_VHT_OPER_INFO)) {
214 struct ieee80211_vht_operation he_oper_vht_cap;
215
216 /*
217 * Set only first 3 bytes (other 2 aren't used in
218 * ieee80211_chandef_vht_oper() anyway)
219 */
220 memcpy(&he_oper_vht_cap, he_oper->optional, 3);
221 he_oper_vht_cap.basic_mcs_set = cpu_to_le16(0);
222
223 if (!ieee80211_chandef_vht_oper(&he_oper_vht_cap,
224 &vht_chandef)) {
225 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
226 sdata_info(sdata,
227 "HE AP VHT information is invalid, disable HE\n");
228 ret = IEEE80211_STA_DISABLE_HE;
229 goto out;
230 }
231 } else if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) {
211 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) 232 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
212 sdata_info(sdata, 233 sdata_info(sdata,
213 "AP VHT information is invalid, disable VHT\n"); 234 "AP VHT information is invalid, disable VHT\n");
@@ -300,12 +321,14 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
300 const struct ieee80211_ht_cap *ht_cap, 321 const struct ieee80211_ht_cap *ht_cap,
301 const struct ieee80211_ht_operation *ht_oper, 322 const struct ieee80211_ht_operation *ht_oper,
302 const struct ieee80211_vht_operation *vht_oper, 323 const struct ieee80211_vht_operation *vht_oper,
324 const struct ieee80211_he_operation *he_oper,
303 const u8 *bssid, u32 *changed) 325 const u8 *bssid, u32 *changed)
304{ 326{
305 struct ieee80211_local *local = sdata->local; 327 struct ieee80211_local *local = sdata->local;
306 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 328 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
307 struct ieee80211_supported_band *sband; 329 struct ieee80211_channel *chan = sdata->vif.bss_conf.chandef.chan;
308 struct ieee80211_channel *chan; 330 struct ieee80211_supported_band *sband =
331 local->hw.wiphy->bands[chan->band];
309 struct cfg80211_chan_def chandef; 332 struct cfg80211_chan_def chandef;
310 u16 ht_opmode; 333 u16 ht_opmode;
311 u32 flags; 334 u32 flags;
@@ -320,6 +343,11 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
320 if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) 343 if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
321 vht_oper = NULL; 344 vht_oper = NULL;
322 345
346 /* don't check HE if we associated as non-HE station */
347 if (ifmgd->flags & IEEE80211_STA_DISABLE_HE ||
348 !ieee80211_get_he_sta_cap(sband))
349 he_oper = NULL;
350
323 if (WARN_ON_ONCE(!sta)) 351 if (WARN_ON_ONCE(!sta))
324 return -EINVAL; 352 return -EINVAL;
325 353
@@ -333,12 +361,9 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
333 sdata->vif.bss_conf.ht_operation_mode = ht_opmode; 361 sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
334 } 362 }
335 363
336 chan = sdata->vif.bss_conf.chandef.chan; 364 /* calculate new channel (type) based on HT/VHT/HE operation IEs */
337 sband = local->hw.wiphy->bands[chan->band];
338
339 /* calculate new channel (type) based on HT/VHT operation IEs */
340 flags = ieee80211_determine_chantype(sdata, sband, chan, 365 flags = ieee80211_determine_chantype(sdata, sband, chan,
341 ht_oper, vht_oper, 366 ht_oper, vht_oper, he_oper,
342 &chandef, true); 367 &chandef, true);
343 368
344 /* 369 /*
@@ -582,6 +607,34 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
582 ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); 607 ieee80211_ie_build_vht_cap(pos, &vht_cap, cap);
583} 608}
584 609
610/* This function determines HE capability flags for the association
611 * and builds the IE.
612 */
613static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
614 struct sk_buff *skb,
615 struct ieee80211_supported_band *sband)
616{
617 u8 *pos;
618 const struct ieee80211_sta_he_cap *he_cap = NULL;
619 u8 he_cap_size;
620
621 he_cap = ieee80211_get_he_sta_cap(sband);
622 if (!he_cap)
623 return;
624
625 /*
626 * TODO: the 1 added is because this temporarily is under the EXTENSION
627 * IE. Get rid of it when it moves.
628 */
629 he_cap_size =
630 2 + 1 + sizeof(he_cap->he_cap_elem) +
631 ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem) +
632 ieee80211_he_ppe_size(he_cap->ppe_thres[0],
633 he_cap->he_cap_elem.phy_cap_info);
634 pos = skb_put(skb, he_cap_size);
635 ieee80211_ie_build_he_cap(pos, he_cap, pos + he_cap_size);
636}
637
585static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) 638static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
586{ 639{
587 struct ieee80211_local *local = sdata->local; 640 struct ieee80211_local *local = sdata->local;
@@ -643,6 +696,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
643 2 + 2 * sband->n_channels + /* supported channels */ 696 2 + 2 * sband->n_channels + /* supported channels */
644 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ 697 2 + sizeof(struct ieee80211_ht_cap) + /* HT */
645 2 + sizeof(struct ieee80211_vht_cap) + /* VHT */ 698 2 + sizeof(struct ieee80211_vht_cap) + /* VHT */
699 2 + 1 + sizeof(struct ieee80211_he_cap_elem) + /* HE */
700 sizeof(struct ieee80211_he_mcs_nss_supp) +
701 IEEE80211_HE_PPE_THRES_MAX_LEN +
646 assoc_data->ie_len + /* extra IEs */ 702 assoc_data->ie_len + /* extra IEs */
647 (assoc_data->fils_kek_len ? 16 /* AES-SIV */ : 0) + 703 (assoc_data->fils_kek_len ? 16 /* AES-SIV */ : 0) +
648 9, /* WMM */ 704 9, /* WMM */
@@ -827,11 +883,41 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
827 offset = noffset; 883 offset = noffset;
828 } 884 }
829 885
886 /* if present, add any custom IEs that go before HE */
887 if (assoc_data->ie_len) {
888 static const u8 before_he[] = {
889 /*
890 * no need to list the ones split off before VHT
891 * or generated here
892 */
893 WLAN_EID_OPMODE_NOTIF,
894 WLAN_EID_EXTENSION, WLAN_EID_EXT_FUTURE_CHAN_GUIDANCE,
895 /* 11ai elements */
896 WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_SESSION,
897 WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_PUBLIC_KEY,
898 WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_KEY_CONFIRM,
899 WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_HLP_CONTAINER,
900 WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN,
901 /* TODO: add 11ah/11aj/11ak elements */
902 };
903
904 /* RIC already taken above, so no need to handle here anymore */
905 noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len,
906 before_he, ARRAY_SIZE(before_he),
907 offset);
908 pos = skb_put(skb, noffset - offset);
909 memcpy(pos, assoc_data->ie + offset, noffset - offset);
910 offset = noffset;
911 }
912
830 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) 913 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
831 ieee80211_add_vht_ie(sdata, skb, sband, 914 ieee80211_add_vht_ie(sdata, skb, sband,
832 &assoc_data->ap_vht_cap); 915 &assoc_data->ap_vht_cap);
833 916
834 /* if present, add any custom non-vendor IEs that go after HT */ 917 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
918 ieee80211_add_he_ie(sdata, skb, sband);
919
920 /* if present, add any custom non-vendor IEs that go after HE */
835 if (assoc_data->ie_len) { 921 if (assoc_data->ie_len) {
836 noffset = ieee80211_ie_split_vendor(assoc_data->ie, 922 noffset = ieee80211_ie_split_vendor(assoc_data->ie,
837 assoc_data->ie_len, 923 assoc_data->ie_len,
@@ -898,6 +984,11 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
898 struct ieee80211_hdr_3addr *nullfunc; 984 struct ieee80211_hdr_3addr *nullfunc;
899 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 985 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
900 986
987 /* Don't send NDPs when STA is connected HE */
988 if (sdata->vif.type == NL80211_IFTYPE_STATION &&
989 !(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
990 return;
991
901 skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif, 992 skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif,
902 !ieee80211_hw_check(&local->hw, DOESNT_SUPPORT_QOS_NDP)); 993 !ieee80211_hw_check(&local->hw, DOESNT_SUPPORT_QOS_NDP));
903 if (!skb) 994 if (!skb)
@@ -929,6 +1020,10 @@ static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
929 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) 1020 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
930 return; 1021 return;
931 1022
1023 /* Don't send NDPs when connected HE */
1024 if (!(sdata->u.mgd.flags & IEEE80211_STA_DISABLE_HE))
1025 return;
1026
932 skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30); 1027 skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30);
933 if (!skb) 1028 if (!skb)
934 return; 1029 return;
@@ -1700,9 +1795,11 @@ static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work)
1700} 1795}
1701 1796
1702/* MLME */ 1797/* MLME */
1703static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, 1798static bool
1704 struct ieee80211_sub_if_data *sdata, 1799ieee80211_sta_wmm_params(struct ieee80211_local *local,
1705 const u8 *wmm_param, size_t wmm_param_len) 1800 struct ieee80211_sub_if_data *sdata,
1801 const u8 *wmm_param, size_t wmm_param_len,
1802 const struct ieee80211_mu_edca_param_set *mu_edca)
1706{ 1803{
1707 struct ieee80211_tx_queue_params params[IEEE80211_NUM_ACS]; 1804 struct ieee80211_tx_queue_params params[IEEE80211_NUM_ACS];
1708 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 1805 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -1749,6 +1846,9 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
1749 sdata->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ 1846 sdata->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
1750 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) 1847 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
1751 uapsd = true; 1848 uapsd = true;
1849 params[ac].mu_edca = !!mu_edca;
1850 if (mu_edca)
1851 params[ac].mu_edca_param_rec = mu_edca->ac_bk;
1752 break; 1852 break;
1753 case 2: /* AC_VI */ 1853 case 2: /* AC_VI */
1754 ac = IEEE80211_AC_VI; 1854 ac = IEEE80211_AC_VI;
@@ -1756,6 +1856,9 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
1756 sdata->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ 1856 sdata->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
1757 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) 1857 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
1758 uapsd = true; 1858 uapsd = true;
1859 params[ac].mu_edca = !!mu_edca;
1860 if (mu_edca)
1861 params[ac].mu_edca_param_rec = mu_edca->ac_vi;
1759 break; 1862 break;
1760 case 3: /* AC_VO */ 1863 case 3: /* AC_VO */
1761 ac = IEEE80211_AC_VO; 1864 ac = IEEE80211_AC_VO;
@@ -1763,6 +1866,9 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
1763 sdata->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ 1866 sdata->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
1764 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) 1867 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
1765 uapsd = true; 1868 uapsd = true;
1869 params[ac].mu_edca = !!mu_edca;
1870 if (mu_edca)
1871 params[ac].mu_edca_param_rec = mu_edca->ac_vo;
1766 break; 1872 break;
1767 case 0: /* AC_BE */ 1873 case 0: /* AC_BE */
1768 default: 1874 default:
@@ -1771,6 +1877,9 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
1771 sdata->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ 1877 sdata->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
1772 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) 1878 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
1773 uapsd = true; 1879 uapsd = true;
1880 params[ac].mu_edca = !!mu_edca;
1881 if (mu_edca)
1882 params[ac].mu_edca_param_rec = mu_edca->ac_be;
1774 break; 1883 break;
1775 } 1884 }
1776 1885
@@ -3021,6 +3130,25 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
3021 goto out; 3130 goto out;
3022 } 3131 }
3023 3132
3133 /*
3134 * If AP doesn't support HT, or it doesn't have HE mandatory IEs, mark
3135 * HE as disabled. If on the 5GHz band, make sure it supports VHT.
3136 */
3137 if (ifmgd->flags & IEEE80211_STA_DISABLE_HT ||
3138 (sband->band == NL80211_BAND_5GHZ &&
3139 ifmgd->flags & IEEE80211_STA_DISABLE_VHT) ||
3140 (!elems.he_cap && !elems.he_operation))
3141 ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
3142
3143 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
3144 (!elems.he_cap || !elems.he_operation)) {
3145 mutex_unlock(&sdata->local->sta_mtx);
3146 sdata_info(sdata,
3147 "HE AP is missing HE capability/operation\n");
3148 ret = false;
3149 goto out;
3150 }
3151
3024 /* Set up internal HT/VHT capabilities */ 3152 /* Set up internal HT/VHT capabilities */
3025 if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) 3153 if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
3026 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, 3154 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
@@ -3030,6 +3158,48 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
3030 ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, 3158 ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
3031 elems.vht_cap_elem, sta); 3159 elems.vht_cap_elem, sta);
3032 3160
3161 if (elems.he_operation && !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
3162 elems.he_cap) {
3163 ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
3164 elems.he_cap,
3165 elems.he_cap_len,
3166 sta);
3167
3168 bss_conf->he_support = sta->sta.he_cap.has_he;
3169 } else {
3170 bss_conf->he_support = false;
3171 }
3172
3173 if (bss_conf->he_support) {
3174 u32 he_oper_params =
3175 le32_to_cpu(elems.he_operation->he_oper_params);
3176
3177 bss_conf->bss_color = he_oper_params &
3178 IEEE80211_HE_OPERATION_BSS_COLOR_MASK;
3179 bss_conf->htc_trig_based_pkt_ext =
3180 (he_oper_params &
3181 IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK) <<
3182 IEEE80211_HE_OPERATION_DFLT_PE_DURATION_OFFSET;
3183 bss_conf->frame_time_rts_th =
3184 (he_oper_params &
3185 IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK) <<
3186 IEEE80211_HE_OPERATION_RTS_THRESHOLD_OFFSET;
3187
3188 bss_conf->multi_sta_back_32bit =
3189 sta->sta.he_cap.he_cap_elem.mac_cap_info[2] &
3190 IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP;
3191
3192 bss_conf->ack_enabled =
3193 sta->sta.he_cap.he_cap_elem.mac_cap_info[2] &
3194 IEEE80211_HE_MAC_CAP2_ACK_EN;
3195
3196 bss_conf->uora_exists = !!elems.uora_element;
3197 if (elems.uora_element)
3198 bss_conf->uora_ocw_range = elems.uora_element[0];
3199
3200 /* TODO: OPEN: what happens if BSS color disable is set? */
3201 }
3202
3033 /* 3203 /*
3034 * Some APs, e.g. Netgear WNDR3700, report invalid HT operation data 3204 * Some APs, e.g. Netgear WNDR3700, report invalid HT operation data
3035 * in their association response, so ignore that data for our own 3205 * in their association response, so ignore that data for our own
@@ -3089,7 +3259,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
3089 if (ifmgd->flags & IEEE80211_STA_DISABLE_WMM) { 3259 if (ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
3090 ieee80211_set_wmm_default(sdata, false, false); 3260 ieee80211_set_wmm_default(sdata, false, false);
3091 } else if (!ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, 3261 } else if (!ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
3092 elems.wmm_param_len)) { 3262 elems.wmm_param_len,
3263 elems.mu_edca_param_set)) {
3093 /* still enable QoS since we might have HT/VHT */ 3264 /* still enable QoS since we might have HT/VHT */
3094 ieee80211_set_wmm_default(sdata, false, true); 3265 ieee80211_set_wmm_default(sdata, false, true);
3095 /* set the disable-WMM flag in this case to disable 3266 /* set the disable-WMM flag in this case to disable
@@ -3603,7 +3774,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
3603 3774
3604 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && 3775 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
3605 ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, 3776 ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
3606 elems.wmm_param_len)) 3777 elems.wmm_param_len,
3778 elems.mu_edca_param_set))
3607 changed |= BSS_CHANGED_QOS; 3779 changed |= BSS_CHANGED_QOS;
3608 3780
3609 /* 3781 /*
@@ -3642,7 +3814,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
3642 3814
3643 if (ieee80211_config_bw(sdata, sta, 3815 if (ieee80211_config_bw(sdata, sta,
3644 elems.ht_cap_elem, elems.ht_operation, 3816 elems.ht_cap_elem, elems.ht_operation,
3645 elems.vht_operation, bssid, &changed)) { 3817 elems.vht_operation, elems.he_operation,
3818 bssid, &changed)) {
3646 mutex_unlock(&local->sta_mtx); 3819 mutex_unlock(&local->sta_mtx);
3647 sdata_info(sdata, 3820 sdata_info(sdata,
3648 "failed to follow AP %pM bandwidth change, disconnect\n", 3821 "failed to follow AP %pM bandwidth change, disconnect\n",
@@ -4279,6 +4452,66 @@ static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata,
4279 return chains; 4452 return chains;
4280} 4453}
4281 4454
4455static bool
4456ieee80211_verify_sta_he_mcs_support(struct ieee80211_supported_band *sband,
4457 const struct ieee80211_he_operation *he_op)
4458{
4459 const struct ieee80211_sta_he_cap *sta_he_cap =
4460 ieee80211_get_he_sta_cap(sband);
4461 u16 ap_min_req_set = le16_to_cpu(he_op->he_mcs_nss_set);
4462 int i;
4463
4464 if (!sta_he_cap || !he_op)
4465 return false;
4466
4467 /* Need to go over for 80MHz, 160MHz and for 80+80 */
4468 for (i = 0; i < 3; i++) {
4469 const struct ieee80211_he_mcs_nss_supp *sta_mcs_nss_supp =
4470 &sta_he_cap->he_mcs_nss_supp;
4471 u16 sta_mcs_map_rx =
4472 le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i]);
4473 u16 sta_mcs_map_tx =
4474 le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i + 1]);
4475 u8 nss;
4476 bool verified = true;
4477
4478 /*
4479 * For each band there is a maximum of 8 spatial streams
4480 * possible. Each of the sta_mcs_map_* is a 16-bit struct built
4481 * of 2 bits per NSS (1-8), with the values defined in enum
4482 * ieee80211_he_mcs_support. Need to make sure STA TX and RX
4483 * capabilities aren't less than the AP's minimum requirements
4484 * for this HE BSS per SS.
4485 * It is enough to find one such band that meets the reqs.
4486 */
4487 for (nss = 8; nss > 0; nss--) {
4488 u8 sta_rx_val = (sta_mcs_map_rx >> (2 * (nss - 1))) & 3;
4489 u8 sta_tx_val = (sta_mcs_map_tx >> (2 * (nss - 1))) & 3;
4490 u8 ap_val = (ap_min_req_set >> (2 * (nss - 1))) & 3;
4491
4492 if (ap_val == IEEE80211_HE_MCS_NOT_SUPPORTED)
4493 continue;
4494
4495 /*
4496 * Make sure the HE AP doesn't require MCSs that aren't
4497 * supported by the client
4498 */
4499 if (sta_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
4500 sta_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
4501 (ap_val > sta_rx_val) || (ap_val > sta_tx_val)) {
4502 verified = false;
4503 break;
4504 }
4505 }
4506
4507 if (verified)
4508 return true;
4509 }
4510
4511 /* If here, STA doesn't meet AP's HE min requirements */
4512 return false;
4513}
4514
4282static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, 4515static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
4283 struct cfg80211_bss *cbss) 4516 struct cfg80211_bss *cbss)
4284{ 4517{
@@ -4287,6 +4520,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
4287 const struct ieee80211_ht_cap *ht_cap = NULL; 4520 const struct ieee80211_ht_cap *ht_cap = NULL;
4288 const struct ieee80211_ht_operation *ht_oper = NULL; 4521 const struct ieee80211_ht_operation *ht_oper = NULL;
4289 const struct ieee80211_vht_operation *vht_oper = NULL; 4522 const struct ieee80211_vht_operation *vht_oper = NULL;
4523 const struct ieee80211_he_operation *he_oper = NULL;
4290 struct ieee80211_supported_band *sband; 4524 struct ieee80211_supported_band *sband;
4291 struct cfg80211_chan_def chandef; 4525 struct cfg80211_chan_def chandef;
4292 int ret; 4526 int ret;
@@ -4342,6 +4576,25 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
4342 } 4576 }
4343 } 4577 }
4344 4578
4579 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
4580 ieee80211_get_he_sta_cap(sband)) {
4581 const struct cfg80211_bss_ies *ies;
4582 const u8 *he_oper_ie;
4583
4584 ies = rcu_dereference(cbss->ies);
4585 he_oper_ie = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_OPERATION,
4586 ies->data, ies->len);
4587 if (he_oper_ie &&
4588 he_oper_ie[1] == ieee80211_he_oper_size(&he_oper_ie[3]))
4589 he_oper = (void *)(he_oper_ie + 3);
4590 else
4591 he_oper = NULL;
4592
4593 if (!he_oper ||
4594 !ieee80211_verify_sta_he_mcs_support(sband, he_oper))
4595 ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
4596 }
4597
4345 /* Allow VHT if at least one channel on the sband supports 80 MHz */ 4598 /* Allow VHT if at least one channel on the sband supports 80 MHz */
4346 have_80mhz = false; 4599 have_80mhz = false;
4347 for (i = 0; i < sband->n_channels; i++) { 4600 for (i = 0; i < sband->n_channels; i++) {
@@ -4358,7 +4611,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
4358 4611
4359 ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, 4612 ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
4360 cbss->channel, 4613 cbss->channel,
4361 ht_oper, vht_oper, 4614 ht_oper, vht_oper, he_oper,
4362 &chandef, false); 4615 &chandef, false);
4363 4616
4364 sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), 4617 sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss),
@@ -4764,8 +5017,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
4764 req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { 5017 req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) {
4765 ifmgd->flags |= IEEE80211_STA_DISABLE_HT; 5018 ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
4766 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; 5019 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
5020 ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
4767 netdev_info(sdata->dev, 5021 netdev_info(sdata->dev,
4768 "disabling HT/VHT due to WEP/TKIP use\n"); 5022 "disabling HE/HT/VHT due to WEP/TKIP use\n");
4769 } 5023 }
4770 } 5024 }
4771 5025