]> git.baikalelectronics.ru Git - kernel.git/commitdiff
nl80211: add support for setting fixed HE rate/gi/ltf
authorMiles Hu <milehu@codeaurora.org>
Tue, 4 Aug 2020 08:16:29 +0000 (10:16 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 27 Aug 2020 12:12:14 +0000 (14:12 +0200)
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>
include/net/cfg80211.h
include/uapi/linux/nl80211.h
net/wireless/nl80211.c

index d9e6b9fbd95ba55ba62bfccdec47378dfaadb382..c9bce9bba51127a56b5315df5d910325496b7701 100644 (file)
@@ -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];
 };
 
index 8cc2b825e4e4f8a557e05df1cd33ad187dffaa94..1a4b922f489fceb09971e869524156bb320f4599 100644 (file)
@@ -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,
index 6ee3bc48d776180fd06ea7ce4341d1d87f70fff4..da0f33c2d2d835ea0ffada25ddbfe79065cc9166 100644 (file)
@@ -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,
-                                                   &params.beacon_rate);
+                                                   &params.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;