aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h1
-rw-r--r--include/uapi/linux/nl80211.h12
-rw-r--r--net/wireless/nl80211.c92
3 files changed, 99 insertions, 6 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 6c3a650f3a8f..80a10212b1b9 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1767,6 +1767,7 @@ struct cfg80211_bitrate_mask {
1767 struct { 1767 struct {
1768 u32 legacy; 1768 u32 legacy;
1769 u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN]; 1769 u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN];
1770 u16 vht_mcs[NL80211_VHT_NSS_MAX];
1770 } control[IEEE80211_NUM_BANDS]; 1771 } control[IEEE80211_NUM_BANDS];
1771}; 1772};
1772/** 1773/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 6e700645cd27..e1307909ecf1 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3112,6 +3112,8 @@ enum nl80211_key_attributes {
3112 * %NL80211_MAX_SUPP_RATES in a single array). 3112 * %NL80211_MAX_SUPP_RATES in a single array).
3113 * @NL80211_TXRATE_HT: HT (MCS) rates allowed for TX rate selection 3113 * @NL80211_TXRATE_HT: HT (MCS) rates allowed for TX rate selection
3114 * in an array of MCS numbers. 3114 * in an array of MCS numbers.
3115 * @NL80211_TXRATE_VHT: VHT rates allowed for TX rate selection,
3116 * see &struct nl80211_txrate_vht
3115 * @__NL80211_TXRATE_AFTER_LAST: internal 3117 * @__NL80211_TXRATE_AFTER_LAST: internal
3116 * @NL80211_TXRATE_MAX: highest TX rate attribute 3118 * @NL80211_TXRATE_MAX: highest TX rate attribute
3117 */ 3119 */
@@ -3119,6 +3121,7 @@ enum nl80211_tx_rate_attributes {
3119 __NL80211_TXRATE_INVALID, 3121 __NL80211_TXRATE_INVALID,
3120 NL80211_TXRATE_LEGACY, 3122 NL80211_TXRATE_LEGACY,
3121 NL80211_TXRATE_HT, 3123 NL80211_TXRATE_HT,
3124 NL80211_TXRATE_VHT,
3122 3125
3123 /* keep last */ 3126 /* keep last */
3124 __NL80211_TXRATE_AFTER_LAST, 3127 __NL80211_TXRATE_AFTER_LAST,
@@ -3126,6 +3129,15 @@ enum nl80211_tx_rate_attributes {
3126}; 3129};
3127 3130
3128#define NL80211_TXRATE_MCS NL80211_TXRATE_HT 3131#define NL80211_TXRATE_MCS NL80211_TXRATE_HT
3132#define NL80211_VHT_NSS_MAX 8
3133
3134/**
3135 * struct nl80211_txrate_vht - VHT MCS/NSS txrate bitmap
3136 * @mcs: MCS bitmap table for each NSS (array index 0 for 1 stream, etc.)
3137 */
3138struct nl80211_txrate_vht {
3139 __u16 mcs[NL80211_VHT_NSS_MAX];
3140};
3129 3141
3130/** 3142/**
3131 * enum nl80211_band - Frequency band 3143 * enum nl80211_band - Frequency band
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 2d0c19c6133b..04681a46eda8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -7328,11 +7328,72 @@ static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
7328 return true; 7328 return true;
7329} 7329}
7330 7330
7331static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
7332{
7333 u16 mcs_mask = 0;
7334
7335 switch (vht_mcs_map) {
7336 case IEEE80211_VHT_MCS_NOT_SUPPORTED:
7337 break;
7338 case IEEE80211_VHT_MCS_SUPPORT_0_7:
7339 mcs_mask = 0x00FF;
7340 break;
7341 case IEEE80211_VHT_MCS_SUPPORT_0_8:
7342 mcs_mask = 0x01FF;
7343 break;
7344 case IEEE80211_VHT_MCS_SUPPORT_0_9:
7345 mcs_mask = 0x03FF;
7346 break;
7347 default:
7348 break;
7349 }
7350
7351 return mcs_mask;
7352}
7353
7354static void vht_build_mcs_mask(u16 vht_mcs_map,
7355 u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
7356{
7357 u8 nss;
7358
7359 for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
7360 vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
7361 vht_mcs_map >>= 2;
7362 }
7363}
7364
7365static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
7366 struct nl80211_txrate_vht *txrate,
7367 u16 mcs[NL80211_VHT_NSS_MAX])
7368{
7369 u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
7370 u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
7371 u8 i;
7372
7373 if (!sband->vht_cap.vht_supported)
7374 return false;
7375
7376 memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
7377
7378 /* Build vht_mcs_mask from VHT capabilities */
7379 vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
7380
7381 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
7382 if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
7383 mcs[i] = txrate->mcs[i];
7384 else
7385 return false;
7386 }
7387
7388 return true;
7389}
7390
7331static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { 7391static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
7332 [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, 7392 [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
7333 .len = NL80211_MAX_SUPP_RATES }, 7393 .len = NL80211_MAX_SUPP_RATES },
7334 [NL80211_TXRATE_HT] = { .type = NLA_BINARY, 7394 [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
7335 .len = NL80211_MAX_SUPP_HT_RATES }, 7395 .len = NL80211_MAX_SUPP_HT_RATES },
7396 [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
7336}; 7397};
7337 7398
7338static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, 7399static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
@@ -7345,6 +7406,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
7345 struct net_device *dev = info->user_ptr[1]; 7406 struct net_device *dev = info->user_ptr[1];
7346 struct nlattr *tx_rates; 7407 struct nlattr *tx_rates;
7347 struct ieee80211_supported_band *sband; 7408 struct ieee80211_supported_band *sband;
7409 u16 vht_tx_mcs_map;
7348 7410
7349 if (!rdev->ops->set_bitrate_mask) 7411 if (!rdev->ops->set_bitrate_mask)
7350 return -EOPNOTSUPP; 7412 return -EOPNOTSUPP;
@@ -7361,6 +7423,12 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
7361 memcpy(mask.control[i].ht_mcs, 7423 memcpy(mask.control[i].ht_mcs,
7362 sband->ht_cap.mcs.rx_mask, 7424 sband->ht_cap.mcs.rx_mask,
7363 sizeof(mask.control[i].ht_mcs)); 7425 sizeof(mask.control[i].ht_mcs));
7426
7427 if (!sband->vht_cap.vht_supported)
7428 continue;
7429
7430 vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
7431 vht_build_mcs_mask(vht_tx_mcs_map, mask.control[i].vht_mcs);
7364 } 7432 }
7365 7433
7366 /* if no rates are given set it back to the defaults */ 7434 /* if no rates are given set it back to the defaults */
@@ -7399,20 +7467,32 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
7399 mask.control[band].ht_mcs)) 7467 mask.control[band].ht_mcs))
7400 return -EINVAL; 7468 return -EINVAL;
7401 } 7469 }
7470 if (tb[NL80211_TXRATE_VHT]) {
7471 if (!vht_set_mcs_mask(
7472 sband,
7473 nla_data(tb[NL80211_TXRATE_VHT]),
7474 mask.control[band].vht_mcs))
7475 return -EINVAL;
7476 }
7402 7477
7403 if (mask.control[band].legacy == 0) { 7478 if (mask.control[band].legacy == 0) {
7404 /* don't allow empty legacy rates if HT 7479 /* don't allow empty legacy rates if HT or VHT
7405 * is not even supported. */ 7480 * are not even supported.
7406 if (!rdev->wiphy.bands[band]->ht_cap.ht_supported) 7481 */
7482 if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
7483 rdev->wiphy.bands[band]->vht_cap.vht_supported))
7407 return -EINVAL; 7484 return -EINVAL;
7408 7485
7409 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) 7486 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
7410 if (mask.control[band].ht_mcs[i]) 7487 if (mask.control[band].ht_mcs[i])
7411 break; 7488 goto out;
7489
7490 for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
7491 if (mask.control[band].vht_mcs[i])
7492 goto out;
7412 7493
7413 /* legacy and mcs rates may not be both empty */ 7494 /* legacy and mcs rates may not be both empty */
7414 if (i == IEEE80211_HT_MCS_MASK_LEN) 7495 return -EINVAL;
7415 return -EINVAL;
7416 } 7496 }
7417 } 7497 }
7418 7498