Skip to content

Commit

Permalink
nl80211: add support for setting fixed HE rate/gi/ltf
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Miles Hu authored and jmberg-intel committed Aug 27, 2020
1 parent 493a0eb commit eb89a6a
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 8 deletions.
3 changes: 3 additions & 0 deletions include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];
};

Expand Down
28 changes: 28 additions & 0 deletions include/uapi/linux/nl80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
*/
Expand All @@ -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,
Expand All @@ -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,
Expand Down
137 changes: 129 additions & 8 deletions net/wireless/nl80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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 */
Expand Down Expand Up @@ -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++)
Expand All @@ -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;
}
Expand Down Expand Up @@ -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,
&params.beacon_rate);
&params.beacon_rate,
dev);
if (err)
return err;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit eb89a6a

Please sign in to comment.