mirror of https://gitee.com/openkylin/linux.git
nl80211: add support for setting fixed HE rate/gi/ltf
This patch adds the nl80211 structs, definitions, policies and parsing code required to pass fixed HE rate, GI and LTF settings. Signed-off-by: Miles Hu <milehu@codeaurora.org> Signed-off-by: John Crispin <john@phrozen.org> Link: https://lore.kernel.org/r/20200804081630.2013619-1-john@phrozen.org [fix comment] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
493a0ebd80
commit
eb89a6a6b7
|
@ -678,7 +678,10 @@ struct cfg80211_bitrate_mask {
|
|||
u32 legacy;
|
||||
u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN];
|
||||
u16 vht_mcs[NL80211_VHT_NSS_MAX];
|
||||
u16 he_mcs[NL80211_HE_NSS_MAX];
|
||||
enum nl80211_txrate_gi gi;
|
||||
enum nl80211_he_gi he_gi;
|
||||
enum nl80211_he_ltf he_ltf;
|
||||
} control[NUM_NL80211_BANDS];
|
||||
};
|
||||
|
||||
|
|
|
@ -3180,6 +3180,18 @@ enum nl80211_he_gi {
|
|||
NL80211_RATE_INFO_HE_GI_3_2,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_he_ltf - HE long training field
|
||||
* @NL80211_RATE_INFO_HE_1xLTF: 3.2 usec
|
||||
* @NL80211_RATE_INFO_HE_2xLTF: 6.4 usec
|
||||
* @NL80211_RATE_INFO_HE_4xLTF: 12.8 usec
|
||||
*/
|
||||
enum nl80211_he_ltf {
|
||||
NL80211_RATE_INFO_HE_1XLTF,
|
||||
NL80211_RATE_INFO_HE_2XLTF,
|
||||
NL80211_RATE_INFO_HE_4XLTF,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_he_ru_alloc - HE RU allocation values
|
||||
* @NL80211_RATE_INFO_HE_RU_ALLOC_26: 26-tone RU allocation
|
||||
|
@ -4735,6 +4747,10 @@ enum nl80211_key_attributes {
|
|||
* @NL80211_TXRATE_VHT: VHT rates allowed for TX rate selection,
|
||||
* see &struct nl80211_txrate_vht
|
||||
* @NL80211_TXRATE_GI: configure GI, see &enum nl80211_txrate_gi
|
||||
* @NL80211_TXRATE_HE: HE rates allowed for TX rate selection,
|
||||
* see &struct nl80211_txrate_he
|
||||
* @NL80211_TXRATE_HE_GI: configure HE GI, 0.8us, 1.6us and 3.2us.
|
||||
* @NL80211_TXRATE_HE_LTF: configure HE LTF, 1XLTF, 2XLTF and 4XLTF.
|
||||
* @__NL80211_TXRATE_AFTER_LAST: internal
|
||||
* @NL80211_TXRATE_MAX: highest TX rate attribute
|
||||
*/
|
||||
|
@ -4744,6 +4760,9 @@ enum nl80211_tx_rate_attributes {
|
|||
NL80211_TXRATE_HT,
|
||||
NL80211_TXRATE_VHT,
|
||||
NL80211_TXRATE_GI,
|
||||
NL80211_TXRATE_HE,
|
||||
NL80211_TXRATE_HE_GI,
|
||||
NL80211_TXRATE_HE_LTF,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_TXRATE_AFTER_LAST,
|
||||
|
@ -4761,6 +4780,15 @@ struct nl80211_txrate_vht {
|
|||
__u16 mcs[NL80211_VHT_NSS_MAX];
|
||||
};
|
||||
|
||||
#define NL80211_HE_NSS_MAX 8
|
||||
/**
|
||||
* struct nl80211_txrate_he - HE MCS/NSS txrate bitmap
|
||||
* @mcs: MCS bitmap table for each NSS (array index 0 for 1 stream, etc.)
|
||||
*/
|
||||
struct nl80211_txrate_he {
|
||||
__u16 mcs[NL80211_HE_NSS_MAX];
|
||||
};
|
||||
|
||||
enum nl80211_txrate_gi {
|
||||
NL80211_TXRATE_DEFAULT_GI,
|
||||
NL80211_TXRATE_FORCE_SGI,
|
||||
|
|
|
@ -336,6 +336,13 @@ static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
|
|||
.len = NL80211_MAX_SUPP_HT_RATES },
|
||||
[NL80211_TXRATE_VHT] = NLA_POLICY_EXACT_LEN_WARN(sizeof(struct nl80211_txrate_vht)),
|
||||
[NL80211_TXRATE_GI] = { .type = NLA_U8 },
|
||||
[NL80211_TXRATE_HE] = NLA_POLICY_EXACT_LEN(sizeof(struct nl80211_txrate_he)),
|
||||
[NL80211_TXRATE_HE_GI] = NLA_POLICY_RANGE(NLA_U8,
|
||||
NL80211_RATE_INFO_HE_GI_0_8,
|
||||
NL80211_RATE_INFO_HE_GI_3_2),
|
||||
[NL80211_TXRATE_HE_LTF] = NLA_POLICY_RANGE(NLA_U8,
|
||||
NL80211_RATE_INFO_HE_1XLTF,
|
||||
NL80211_RATE_INFO_HE_4XLTF),
|
||||
};
|
||||
|
||||
static const struct nla_policy
|
||||
|
@ -4430,21 +4437,106 @@ static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
|
|||
return true;
|
||||
}
|
||||
|
||||
static u16 he_mcs_map_to_mcs_mask(u8 he_mcs_map)
|
||||
{
|
||||
switch (he_mcs_map) {
|
||||
case IEEE80211_HE_MCS_NOT_SUPPORTED:
|
||||
return 0;
|
||||
case IEEE80211_HE_MCS_SUPPORT_0_7:
|
||||
return 0x00FF;
|
||||
case IEEE80211_HE_MCS_SUPPORT_0_9:
|
||||
return 0x03FF;
|
||||
case IEEE80211_HE_MCS_SUPPORT_0_11:
|
||||
return 0xFFF;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void he_build_mcs_mask(u16 he_mcs_map,
|
||||
u16 he_mcs_mask[NL80211_HE_NSS_MAX])
|
||||
{
|
||||
u8 nss;
|
||||
|
||||
for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++) {
|
||||
he_mcs_mask[nss] = he_mcs_map_to_mcs_mask(he_mcs_map & 0x03);
|
||||
he_mcs_map >>= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static u16 he_get_txmcsmap(struct genl_info *info,
|
||||
const struct ieee80211_sta_he_cap *he_cap)
|
||||
{
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
__le16 tx_mcs;
|
||||
|
||||
switch (wdev->chandef.width) {
|
||||
case NL80211_CHAN_WIDTH_80P80:
|
||||
tx_mcs = he_cap->he_mcs_nss_supp.tx_mcs_80p80;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_160:
|
||||
tx_mcs = he_cap->he_mcs_nss_supp.tx_mcs_160;
|
||||
break;
|
||||
default:
|
||||
tx_mcs = he_cap->he_mcs_nss_supp.tx_mcs_80;
|
||||
break;
|
||||
}
|
||||
return le16_to_cpu(tx_mcs);
|
||||
}
|
||||
|
||||
static bool he_set_mcs_mask(struct genl_info *info,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_supported_band *sband,
|
||||
struct nl80211_txrate_he *txrate,
|
||||
u16 mcs[NL80211_HE_NSS_MAX])
|
||||
{
|
||||
const struct ieee80211_sta_he_cap *he_cap;
|
||||
u16 tx_mcs_mask[NL80211_HE_NSS_MAX] = {};
|
||||
u16 tx_mcs_map = 0;
|
||||
u8 i;
|
||||
|
||||
he_cap = ieee80211_get_he_iftype_cap(sband, wdev->iftype);
|
||||
if (!he_cap)
|
||||
return false;
|
||||
|
||||
memset(mcs, 0, sizeof(u16) * NL80211_HE_NSS_MAX);
|
||||
|
||||
tx_mcs_map = he_get_txmcsmap(info, he_cap);
|
||||
|
||||
/* Build he_mcs_mask from HE capabilities */
|
||||
he_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
|
||||
|
||||
for (i = 0; i < NL80211_HE_NSS_MAX; i++) {
|
||||
if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
|
||||
mcs[i] = txrate->mcs[i];
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
|
||||
struct nlattr *attrs[],
|
||||
enum nl80211_attrs attr,
|
||||
struct cfg80211_bitrate_mask *mask)
|
||||
struct cfg80211_bitrate_mask *mask,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct nlattr *tb[NL80211_TXRATE_MAX + 1];
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int rem, i;
|
||||
struct nlattr *tx_rates;
|
||||
struct ieee80211_supported_band *sband;
|
||||
u16 vht_tx_mcs_map;
|
||||
u16 vht_tx_mcs_map, he_tx_mcs_map;
|
||||
|
||||
memset(mask, 0, sizeof(*mask));
|
||||
/* Default to all rates enabled */
|
||||
for (i = 0; i < NUM_NL80211_BANDS; i++) {
|
||||
const struct ieee80211_sta_he_cap *he_cap;
|
||||
|
||||
sband = rdev->wiphy.bands[i];
|
||||
|
||||
if (!sband)
|
||||
|
@ -4460,6 +4552,16 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
|
|||
|
||||
vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
|
||||
vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs);
|
||||
|
||||
he_cap = ieee80211_get_he_iftype_cap(sband, wdev->iftype);
|
||||
if (!he_cap)
|
||||
continue;
|
||||
|
||||
he_tx_mcs_map = he_get_txmcsmap(info, he_cap);
|
||||
he_build_mcs_mask(he_tx_mcs_map, mask->control[i].he_mcs);
|
||||
|
||||
mask->control[i].he_gi = 0xFF;
|
||||
mask->control[i].he_ltf = 0xFF;
|
||||
}
|
||||
|
||||
/* if no rates are given set it back to the defaults */
|
||||
|
@ -4515,13 +4617,25 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
|
|||
if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI)
|
||||
return -EINVAL;
|
||||
}
|
||||
if (tb[NL80211_TXRATE_HE] &&
|
||||
!he_set_mcs_mask(info, wdev, sband,
|
||||
nla_data(tb[NL80211_TXRATE_HE]),
|
||||
mask->control[band].he_mcs))
|
||||
return -EINVAL;
|
||||
if (tb[NL80211_TXRATE_HE_GI])
|
||||
mask->control[band].he_gi =
|
||||
nla_get_u8(tb[NL80211_TXRATE_HE_GI]);
|
||||
if (tb[NL80211_TXRATE_HE_LTF])
|
||||
mask->control[band].he_ltf =
|
||||
nla_get_u8(tb[NL80211_TXRATE_HE_LTF]);
|
||||
|
||||
if (mask->control[band].legacy == 0) {
|
||||
/* don't allow empty legacy rates if HT or VHT
|
||||
/* don't allow empty legacy rates if HT, VHT or HE
|
||||
* are not even supported.
|
||||
*/
|
||||
if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
|
||||
rdev->wiphy.bands[band]->vht_cap.vht_supported))
|
||||
rdev->wiphy.bands[band]->vht_cap.vht_supported ||
|
||||
ieee80211_get_he_iftype_cap(sband, wdev->iftype)))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
|
||||
|
@ -4532,6 +4646,10 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
|
|||
if (mask->control[band].vht_mcs[i])
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < NL80211_HE_NSS_MAX; i++)
|
||||
if (mask->control[band].he_mcs[i])
|
||||
goto out;
|
||||
|
||||
/* legacy and mcs rates may not be both empty */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -4976,7 +5094,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|||
if (info->attrs[NL80211_ATTR_TX_RATES]) {
|
||||
err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
|
||||
NL80211_ATTR_TX_RATES,
|
||||
¶ms.beacon_rate);
|
||||
¶ms.beacon_rate,
|
||||
dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -10780,7 +10899,8 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
|
||||
NL80211_ATTR_TX_RATES, &mask);
|
||||
NL80211_ATTR_TX_RATES, &mask,
|
||||
dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -11388,7 +11508,8 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
|
|||
if (info->attrs[NL80211_ATTR_TX_RATES]) {
|
||||
err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
|
||||
NL80211_ATTR_TX_RATES,
|
||||
&setup.beacon_rate);
|
||||
&setup.beacon_rate,
|
||||
dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -14168,7 +14289,7 @@ static int parse_tid_conf(struct cfg80211_registered_device *rdev,
|
|||
if (tid_conf->txrate_type != NL80211_TX_RATE_AUTOMATIC) {
|
||||
attr = NL80211_TID_CONFIG_ATTR_TX_RATE;
|
||||
err = nl80211_parse_tx_bitrate_mask(info, attrs, attr,
|
||||
&tid_conf->txrate_mask);
|
||||
&tid_conf->txrate_mask, dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
Loading…
Reference in New Issue