diff options
-rw-r--r-- | include/net/cfg80211.h | 1 | ||||
-rw-r--r-- | include/uapi/linux/nl80211.h | 12 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 92 |
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 | */ | ||
3138 | struct 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 | ||
7331 | static 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 | |||
7354 | static 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 | |||
7365 | static 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 | |||
7331 | static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { | 7391 | static 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 | ||
7338 | static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | 7399 | static 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 | ||