aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorJanusz Dziedzic <janusz.dziedzic@tieto.com>2013-12-05 14:42:58 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-12-16 10:05:17 -0500
commit204e35a91c4b3327b7239d7687fbd4923edbbf08 (patch)
tree5cdcf56ed93325e22a9554e3be803278ed0b8c7b /net/wireless/nl80211.c
parent31f1f4ec51bd264ba133ff0211b241546ba95c9d (diff)
nl80211: add VHT support for set_bitrate_mask
Add VHT MCS/NSS set support for nl80211_set_tx_bitrate_mask(). This should be used mainly for test purpose, to check different MCS/NSS VHT combinations. Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c92
1 files changed, 86 insertions, 6 deletions
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