Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Janusz Dziedzic and committed by
Johannes Berg
204e35a9 31f1f4ec

+99 -6
+1
include/net/cfg80211.h
··· 1767 1767 struct { 1768 1768 u32 legacy; 1769 1769 u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN]; 1770 + u16 vht_mcs[NL80211_VHT_NSS_MAX]; 1770 1771 } control[IEEE80211_NUM_BANDS]; 1771 1772 }; 1772 1773 /**
+12
include/uapi/linux/nl80211.h
··· 3112 3112 * %NL80211_MAX_SUPP_RATES in a single array). 3113 3113 * @NL80211_TXRATE_HT: HT (MCS) rates allowed for TX rate selection 3114 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 3117 * @__NL80211_TXRATE_AFTER_LAST: internal 3116 3118 * @NL80211_TXRATE_MAX: highest TX rate attribute 3117 3119 */ ··· 3121 3119 __NL80211_TXRATE_INVALID, 3122 3120 NL80211_TXRATE_LEGACY, 3123 3121 NL80211_TXRATE_HT, 3122 + NL80211_TXRATE_VHT, 3124 3123 3125 3124 /* keep last */ 3126 3125 __NL80211_TXRATE_AFTER_LAST, ··· 3129 3126 }; 3130 3127 3131 3128 #define NL80211_TXRATE_MCS NL80211_TXRATE_HT 3129 + #define NL80211_VHT_NSS_MAX 8 3130 + 3131 + /** 3132 + * struct nl80211_txrate_vht - VHT MCS/NSS txrate bitmap 3133 + * @mcs: MCS bitmap table for each NSS (array index 0 for 1 stream, etc.) 3134 + */ 3135 + struct nl80211_txrate_vht { 3136 + __u16 mcs[NL80211_VHT_NSS_MAX]; 3137 + }; 3132 3138 3133 3139 /** 3134 3140 * enum nl80211_band - Frequency band
+86 -6
net/wireless/nl80211.c
··· 7328 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 7391 static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { 7332 7392 [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, 7333 7393 .len = NL80211_MAX_SUPP_RATES }, 7334 7394 [NL80211_TXRATE_HT] = { .type = NLA_BINARY, 7335 7395 .len = NL80211_MAX_SUPP_HT_RATES }, 7396 + [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)}, 7336 7397 }; 7337 7398 7338 7399 static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, ··· 7406 7345 struct net_device *dev = info->user_ptr[1]; 7407 7346 struct nlattr *tx_rates; 7408 7347 struct ieee80211_supported_band *sband; 7348 + u16 vht_tx_mcs_map; 7409 7349 7410 7350 if (!rdev->ops->set_bitrate_mask) 7411 7351 return -EOPNOTSUPP; ··· 7423 7361 memcpy(mask.control[i].ht_mcs, 7424 7362 sband->ht_cap.mcs.rx_mask, 7425 7363 sizeof(mask.control[i].ht_mcs)); 7364 + 7365 + if (!sband->vht_cap.vht_supported) 7366 + continue; 7367 + 7368 + vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); 7369 + vht_build_mcs_mask(vht_tx_mcs_map, mask.control[i].vht_mcs); 7426 7370 } 7427 7371 7428 7372 /* if no rates are given set it back to the defaults */ ··· 7467 7399 mask.control[band].ht_mcs)) 7468 7400 return -EINVAL; 7469 7401 } 7402 + if (tb[NL80211_TXRATE_VHT]) { 7403 + if (!vht_set_mcs_mask( 7404 + sband, 7405 + nla_data(tb[NL80211_TXRATE_VHT]), 7406 + mask.control[band].vht_mcs)) 7407 + return -EINVAL; 7408 + } 7470 7409 7471 7410 if (mask.control[band].legacy == 0) { 7472 - /* don't allow empty legacy rates if HT 7473 - * is not even supported. */ 7474 - if (!rdev->wiphy.bands[band]->ht_cap.ht_supported) 7411 + /* don't allow empty legacy rates if HT or VHT 7412 + * are not even supported. 7413 + */ 7414 + if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported || 7415 + rdev->wiphy.bands[band]->vht_cap.vht_supported)) 7475 7416 return -EINVAL; 7476 7417 7477 7418 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) 7478 7419 if (mask.control[band].ht_mcs[i]) 7479 - break; 7420 + goto out; 7421 + 7422 + for (i = 0; i < NL80211_VHT_NSS_MAX; i++) 7423 + if (mask.control[band].vht_mcs[i]) 7424 + goto out; 7480 7425 7481 7426 /* legacy and mcs rates may not be both empty */ 7482 - if (i == IEEE80211_HT_MCS_MASK_LEN) 7483 - return -EINVAL; 7427 + return -EINVAL; 7484 7428 } 7485 7429 } 7486 7430