2012-01-28 16:25:36

by Simon Wunderlich

[permalink] [raw]
Subject: [PATCHv3 0/2] [RESEND] add support for mcs masks

This patchset is simply the rebased version of PATCHv2, which received
quite a few comments, but in the end we agreed to leave it as it is.
As the patchset has not been merged so far, I'm resending it. If there
are any comments/objections, please let me know. :)

(original) description:

This patchset adds support for fixed HT datarates. The configuration is
set through nl80211, and now accepts MCS masks next to the legacy masks.

A user may also choose to only use HT datarates and no legacy rates at all -
- as always when fiddling with datarates, he should know what he's doing,
and a fallback in the rate matching functions allow to use the rate controls
selected rate if no matching rate was found. The rate matching was enhanced
to consider MCS rates as well.

I have tested this feature in IBSS mode with ath9k devices and with and without
NoAcks, and (at least for me) it works as expected.

There is an iw patch as well to make use of this feature.

It should apply well on the latest wireless-testing kernel.

Changes to previous versions:
* fix NL80211_MAX_SUPP_HT_RATES and add bug assertion
* copy mcs rates from sband into mask
* add sanity check for rate index
* various formatting clean up

Signed-off-by: Simon Wunderlich <[email protected]>
Signed-off-by: Mathias Kretschmer <[email protected]>

Simon Wunderlich (2):
nl80211: add support for mcs masks
mac80211: add support for mcs masks

include/linux/nl80211.h | 4 +
include/net/cfg80211.h | 3 +-
include/net/mac80211.h | 1 +
net/mac80211/cfg.c | 5 +-
net/mac80211/debugfs_netdev.c | 34 +++++++++++
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/iface.c | 7 ++
net/mac80211/rate.c | 124 ++++++++++++++++++++++++++++++++++++++---
net/mac80211/tx.c | 5 ++
net/wireless/nl80211.c | 61 ++++++++++++++++++++-
10 files changed, 233 insertions(+), 12 deletions(-)

--
1.7.8.3



2012-01-28 16:25:37

by Simon Wunderlich

[permalink] [raw]
Subject: [PATCH 2/2] iw: remove ifdefs for mcs mask

These are enums, not defines. Therefore the ifdef check can never be
true.

Signed-off-by: Simon Wunderlich <[email protected]>
Signed-off-by: Mathias Kretschmer <[email protected]>
---
bitrate.c | 20 ++------------------
1 files changed, 2 insertions(+), 18 deletions(-)

diff --git a/bitrate.c b/bitrate.c
index cefd150..22b863e 100644
--- a/bitrate.c
+++ b/bitrate.c
@@ -17,12 +17,10 @@ static int handle_bitrates(struct nl80211_state *state,
uint8_t *legacy = NULL;
int *n_legacy = NULL;
bool have_mcs_24 = false, have_mcs_5 = false;
-#ifdef NL80211_TXRATE_MCS
uint8_t mcs_24[77], mcs_5[77];
int n_mcs_24 = 0, n_mcs_5 = 0;
uint8_t *mcs = NULL;
int *n_mcs = NULL;
-#endif
enum {
S_NONE,
S_LEGACY,
@@ -32,9 +30,7 @@ static int handle_bitrates(struct nl80211_state *state,
for (i = 0; i < argc; i++) {
char *end;
double tmpd;
-#ifdef NL80211_TXRATE_MCS
long tmpl;
-#endif

if (strcmp(argv[i], "legacy-2.4") == 0) {
if (have_legacy_24)
@@ -51,7 +47,6 @@ static int handle_bitrates(struct nl80211_state *state,
n_legacy = &n_legacy_5;
have_legacy_5 = true;
}
-#ifdef NL80211_TXRATE_MCS
else if (strcmp(argv[i], "mcs-2.4") == 0) {
if (have_mcs_24)
return 1;
@@ -67,7 +62,6 @@ static int handle_bitrates(struct nl80211_state *state,
n_mcs = &n_mcs_5;
have_mcs_5 = true;
}
-#endif
else switch (parser_state) {
case S_LEGACY:
tmpd = strtod(argv[i], &end);
@@ -78,7 +72,6 @@ static int handle_bitrates(struct nl80211_state *state,
legacy[(*n_legacy)++] = tmpd * 2;
break;
case S_MCS:
-#ifdef NL80211_TXRATE_MCS
tmpl = strtol(argv[i], &end, 0);
if (*end != '\0')
return 1;
@@ -86,7 +79,6 @@ static int handle_bitrates(struct nl80211_state *state,
return 1;
mcs[(*n_mcs)++] = tmpl;
break;
-#endif
default:
return 1;
}
@@ -102,10 +94,8 @@ static int handle_bitrates(struct nl80211_state *state,
goto nla_put_failure;
if (have_legacy_24)
nla_put(msg, NL80211_TXRATE_LEGACY, n_legacy_24, legacy_24);
-#ifdef NL80211_TXRATE_MCS
if (have_mcs_24)
nla_put(msg, NL80211_TXRATE_MCS, n_mcs_24, mcs_24);
-#endif
nla_nest_end(msg, nl_band);
}

@@ -115,10 +105,8 @@ static int handle_bitrates(struct nl80211_state *state,
goto nla_put_failure;
if (have_legacy_5)
nla_put(msg, NL80211_TXRATE_LEGACY, n_legacy_5, legacy_5);
-#ifdef NL80211_TXRATE_MCS
if (have_mcs_5)
nla_put(msg, NL80211_TXRATE_MCS, n_mcs_5, mcs_5);
-#endif
nla_nest_end(msg, nl_band);
}

@@ -130,13 +118,9 @@ static int handle_bitrates(struct nl80211_state *state,
}

#define DESCR_LEGACY "[legacy-<2.4|5> <legacy rate in Mbps>*]"
-#ifdef NL80211_TXRATE_MCS
#define DESCR DESCR_LEGACY " [mcs-<2.4|5> <MCS index>*]"
-#else
-#define DESCR DESCR_LEGACY
-#endif

-COMMAND(set, bitrates, DESCR, NL80211_CMD_SET_TX_BITRATE_MASK, 0, CIB_NETDEV,
- handle_bitrates,
+COMMAND(set, bitrates, "[legacy-<2.4|5> <legacy rate in Mbps>*] [mcs-<2.4|5> <MCS index>*]",
+ NL80211_CMD_SET_TX_BITRATE_MASK, 0, CIB_NETDEV, handle_bitrates,
"Sets up the specified rate masks.\n"
"Not passing any arguments would clear the existing mask (if any).");
--
1.7.7.3


2012-01-28 16:25:36

by Simon Wunderlich

[permalink] [raw]
Subject: [PATCHv3 1/2] nl80211: add support for mcs masks

Allow to set mcs masks through nl80211. We also allow to set MCS
rates but no legacy rates (and vice versa).

Signed-off-by: Simon Wunderlich <[email protected]>
Signed-off-by: Mathias Kretschmer <[email protected]>
---
include/linux/nl80211.h | 4 +++
include/net/cfg80211.h | 3 +-
net/wireless/nl80211.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 4f98fae..ad56e21 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1475,6 +1475,7 @@ enum nl80211_attrs {
#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS

#define NL80211_MAX_SUPP_RATES 32
+#define NL80211_MAX_SUPP_HT_RATES 77
#define NL80211_MAX_SUPP_REG_RULES 32
#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
@@ -2405,12 +2406,15 @@ enum nl80211_key_attributes {
* in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with
* 1 = 500 kbps) but without the IE length restriction (at most
* %NL80211_MAX_SUPP_RATES in a single array).
+ * @NL80211_TXRATE_MCS: HT (MCS) rates allowed for TX rate selection
+ * in an array of MCS numbers.
* @__NL80211_TXRATE_AFTER_LAST: internal
* @NL80211_TXRATE_MAX: highest TX rate attribute
*/
enum nl80211_tx_rate_attributes {
__NL80211_TXRATE_INVALID,
NL80211_TXRATE_LEGACY,
+ NL80211_TXRATE_MCS,

/* keep last */
__NL80211_TXRATE_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 5bb3ed4..2964205 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1232,8 +1232,7 @@ enum wiphy_params_flags {
struct cfg80211_bitrate_mask {
struct {
u32 legacy;
- /* TODO: add support for masking MCS rates; e.g.: */
- /* u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; */
+ u8 mcs[IEEE80211_HT_MCS_MASK_LEN];
} control[IEEE80211_NUM_BANDS];
};
/**
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c42173f..c910b07 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5393,9 +5393,39 @@ static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
return mask;
}

+static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
+ u8 *rates, u8 rates_len,
+ u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
+{
+ u8 i;
+
+ memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
+
+ for (i = 0; i < rates_len; i++) {
+ int ridx, rbit;
+
+ ridx = rates[i] / 8;
+ rbit = BIT(rates[i] % 8);
+
+ /* check validity */
+ if ((ridx < 0) || (ridx > IEEE80211_HT_MCS_MASK_LEN))
+ return false;
+
+ /* check availability */
+ if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
+ mcs[ridx] |= rbit;
+ else
+ return false;
+ }
+
+ return true;
+}
+
static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
[NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
.len = NL80211_MAX_SUPP_RATES },
+ [NL80211_TXRATE_MCS] = { .type = NLA_BINARY,
+ .len = NL80211_MAX_SUPP_HT_RATES },
};

static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
@@ -5421,12 +5451,20 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
sband = rdev->wiphy.bands[i];
mask.control[i].legacy =
sband ? (1 << sband->n_bitrates) - 1 : 0;
+ if (sband)
+ memcpy(mask.control[i].mcs,
+ sband->ht_cap.mcs.rx_mask,
+ sizeof(mask.control[i].mcs));
+ else
+ memset(mask.control[i].mcs, 0,
+ sizeof(mask.control[i].mcs));
}

/*
* The nested attribute uses enum nl80211_band as the index. This maps
* directly to the enum ieee80211_band values used in cfg80211.
*/
+ BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem)
{
enum ieee80211_band band = nla_type(tx_rates);
@@ -5442,7 +5480,28 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
sband,
nla_data(tb[NL80211_TXRATE_LEGACY]),
nla_len(tb[NL80211_TXRATE_LEGACY]));
- if (mask.control[band].legacy == 0)
+ }
+ if (tb[NL80211_TXRATE_MCS]) {
+ if (!ht_rateset_to_mask(
+ sband,
+ nla_data(tb[NL80211_TXRATE_MCS]),
+ nla_len(tb[NL80211_TXRATE_MCS]),
+ mask.control[band].mcs))
+ return -EINVAL;
+ }
+
+ if (mask.control[band].legacy == 0) {
+ /* don't allow empty legacy rates if HT
+ * is not even supported. */
+ if (!rdev->wiphy.bands[band]->ht_cap.ht_supported)
+ return -EINVAL;
+
+ for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
+ if (mask.control[band].mcs[i])
+ break;
+
+ /* legacy and mcs rates may not be both empty */
+ if (i == IEEE80211_HT_MCS_MASK_LEN)
return -EINVAL;
}
}
--
1.7.8.3


2012-01-28 16:25:37

by Simon Wunderlich

[permalink] [raw]
Subject: [PATCHv3 2/2] mac80211: add support for mcs masks

* Handle MCS masks set by the user.
* Match rates provided by the rate control algorithm to the mask set,
also in HT mode, and switch back to legacy mode if necessary.
* add debugfs files to observate the rate selection

Signed-off-by: Simon Wunderlich <[email protected]>
Signed-off-by: Mathias Kretschmer <[email protected]>
---
include/net/mac80211.h | 1 +
net/mac80211/cfg.c | 5 +-
net/mac80211/debugfs_netdev.c | 34 +++++++++++
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/iface.c | 7 ++
net/mac80211/rate.c | 124 ++++++++++++++++++++++++++++++++++++++---
net/mac80211/tx.c | 5 ++
7 files changed, 168 insertions(+), 9 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 6501858..520eb4c 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3551,6 +3551,7 @@ struct ieee80211_tx_rate_control {
bool rts, short_preamble;
u8 max_rate_idx;
u32 rate_idx_mask;
+ u8 rate_idx_mcs_mask[IEEE80211_HT_MCS_MASK_LEN];
bool bss;
};

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 9846078..9c48db7 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1908,8 +1908,11 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
return ret;
}

- for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
+ memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs,
+ sizeof(mask->control[i].mcs));
+ }

return 0;
}
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 81d12e6..510ed1d 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -87,6 +87,21 @@ static ssize_t ieee80211_if_fmt_##name( \
#define IEEE80211_IF_FMT_SIZE(name, field) \
IEEE80211_IF_FMT(name, field, "%zd\n")

+#define IEEE80211_IF_FMT_HEXARRAY(name, field) \
+static ssize_t ieee80211_if_fmt_##name( \
+ const struct ieee80211_sub_if_data *sdata, \
+ char *buf, int buflen) \
+{ \
+ char *p = buf; \
+ int i; \
+ for (i = 0; i < sizeof(sdata->field); i++) { \
+ p += scnprintf(p, buflen + buf - p, "%.2x ", \
+ sdata->field[i]); \
+ } \
+ p += scnprintf(p, buflen + buf - p, "\n"); \
+ return p - buf; \
+}
+
#define IEEE80211_IF_FMT_ATOMIC(name, field) \
static ssize_t ieee80211_if_fmt_##name( \
const struct ieee80211_sub_if_data *sdata, \
@@ -148,6 +163,11 @@ IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ],
HEX);
IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
HEX);
+IEEE80211_IF_FILE(rc_rateidx_mcs_mask_2ghz,
+ rc_rateidx_mcs_mask[IEEE80211_BAND_2GHZ], HEXARRAY);
+IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz,
+ rc_rateidx_mcs_mask[IEEE80211_BAND_5GHZ], HEXARRAY);
+
IEEE80211_IF_FILE(flags, flags, HEX);
IEEE80211_IF_FILE(state, state, LHEX);
IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC);
@@ -442,6 +462,8 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(channel_type);
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
+ DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
+ DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);

DEBUGFS_ADD(bssid);
DEBUGFS_ADD(aid);
@@ -459,6 +481,8 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(channel_type);
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
+ DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
+ DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);

DEBUGFS_ADD(num_sta_authorized);
DEBUGFS_ADD(num_sta_ps);
@@ -469,6 +493,12 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)

static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
{
+ DEBUGFS_ADD(channel_type);
+ DEBUGFS_ADD(rc_rateidx_mask_2ghz);
+ DEBUGFS_ADD(rc_rateidx_mask_5ghz);
+ DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
+ DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
+
DEBUGFS_ADD_MODE(tsf, 0600);
}

@@ -480,6 +510,8 @@ static void add_wds_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(channel_type);
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
+ DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
+ DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);

DEBUGFS_ADD(peer);
}
@@ -492,6 +524,8 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(channel_type);
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
+ DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
+ DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
}

static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ca6486b..d47e8c1 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -646,6 +646,7 @@ struct ieee80211_sub_if_data {

/* bitmap of allowed (non-MCS) rate indexes for rate control */
u32 rc_rateidx_mask[IEEE80211_NUM_BANDS];
+ u8 rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN];

union {
struct ieee80211_if_ap ap;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 01a21c2..8c20ccb 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1181,6 +1181,13 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
sband = local->hw.wiphy->bands[i];
sdata->rc_rateidx_mask[i] =
sband ? (1 << sband->n_bitrates) - 1 : 0;
+ if (sband)
+ memcpy(sdata->rc_rateidx_mcs_mask[i],
+ sband->ht_cap.mcs.rx_mask,
+ sizeof(sdata->rc_rateidx_mcs_mask[i]));
+ else
+ memset(sdata->rc_rateidx_mcs_mask[i], 0,
+ sizeof(sdata->rc_rateidx_mcs_mask[i]));
}

/* setup type-dependent data */
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index a21110a..3fef26d 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -289,8 +289,8 @@ bool rate_control_send_low(struct ieee80211_sta *sta,
}
EXPORT_SYMBOL(rate_control_send_low);

-static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
- int n_bitrates, u32 mask)
+static bool rate_idx_match_legacy_mask(struct ieee80211_tx_rate *rate,
+ int n_bitrates, u32 mask)
{
int j;

@@ -299,7 +299,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
if (mask & (1 << j)) {
/* Okay, found a suitable rate. Use it. */
rate->idx = j;
- return;
+ return true;
}
}

@@ -308,6 +308,112 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
if (mask & (1 << j)) {
/* Okay, found a suitable rate. Use it. */
rate->idx = j;
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool rate_idx_match_mcs_mask(struct ieee80211_tx_rate *rate,
+ u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
+{
+ int i, j;
+ int ridx, rbit;
+
+ ridx = rate->idx / 8;
+ rbit = rate->idx % 8;
+
+ /* sanity check */
+ if (ridx < 0 || ridx > IEEE80211_HT_MCS_MASK_LEN)
+ return false;
+
+ /* See whether the selected rate or anything below it is allowed. */
+ for (i = ridx; i >= 0; i--) {
+ for (j = rbit; j >= 0; j--)
+ if (mcs_mask[i] & BIT(j)) {
+ rate->idx = i * 8 + j;
+ return true;
+ }
+ rbit = 7;
+ }
+
+ /* Try to find a higher rate that would be allowed */
+ ridx = (rate->idx + 1) / 8;
+ rbit = (rate->idx + 1) % 8;
+
+ for (i = ridx; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+ for (j = rbit; j < 8; j++)
+ if (mcs_mask[i] & BIT(j)) {
+ rate->idx = i * 8 + j;
+ return true;
+ }
+ rbit = 0;
+ }
+ return false;
+}
+
+
+
+static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
+ struct ieee80211_tx_rate_control *txrc,
+ u32 mask,
+ u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
+{
+ struct ieee80211_tx_rate alt_rate;
+
+ /* handle HT rates */
+ if (rate->flags & IEEE80211_TX_RC_MCS) {
+ if (rate_idx_match_mcs_mask(rate, mcs_mask))
+ return;
+
+ /* also try the legacy rates. */
+ alt_rate.idx = 0;
+ /* keep protection flags */
+ alt_rate.flags = rate->flags &
+ (IEEE80211_TX_RC_USE_RTS_CTS |
+ IEEE80211_TX_RC_USE_CTS_PROTECT |
+ IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
+ alt_rate.count = rate->count;
+ if (rate_idx_match_legacy_mask(&alt_rate,
+ txrc->sband->n_bitrates,
+ mask)) {
+ *rate = alt_rate;
+ return;
+ }
+ } else {
+ struct sk_buff *skb = txrc->skb;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ __le16 fc;
+
+ /* handle legacy rates */
+ if (rate_idx_match_legacy_mask(rate, txrc->sband->n_bitrates,
+ mask))
+ return;
+
+ /* if HT BSS, and we handle a data frame, also try HT rates */
+ if (txrc->bss_conf->channel_type == NL80211_CHAN_NO_HT)
+ return;
+
+ fc = hdr->frame_control;
+ if (!ieee80211_is_data(fc))
+ return;
+
+ alt_rate.idx = 0;
+ /* keep protection flags */
+ alt_rate.flags = rate->flags &
+ (IEEE80211_TX_RC_USE_RTS_CTS |
+ IEEE80211_TX_RC_USE_CTS_PROTECT |
+ IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
+ alt_rate.count = rate->count;
+
+ alt_rate.flags |= IEEE80211_TX_RC_MCS;
+
+ if ((txrc->bss_conf->channel_type == NL80211_CHAN_HT40MINUS) ||
+ (txrc->bss_conf->channel_type == NL80211_CHAN_HT40PLUS))
+ alt_rate.flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+
+ if (rate_idx_match_mcs_mask(&alt_rate, mcs_mask)) {
+ *rate = alt_rate;
return;
}
}
@@ -331,6 +437,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
int i;
u32 mask;
+ u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN];

if (sta) {
ista = &sta->sta;
@@ -354,10 +461,14 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
* the common case.
*/
mask = sdata->rc_rateidx_mask[info->band];
+ memcpy(mcs_mask, sdata->rc_rateidx_mcs_mask[info->band],
+ sizeof(mcs_mask));
if (mask != (1 << txrc->sband->n_bitrates) - 1) {
if (sta) {
/* Filter out rates that the STA does not support */
mask &= sta->sta.supp_rates[info->band];
+ for (i = 0; i < sizeof(mcs_mask); i++)
+ mcs_mask[i] &= sta->sta.ht_cap.mcs.rx_mask[i];
}
/*
* Make sure the rate index selected for each TX rate is
@@ -368,11 +479,8 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
/* Skip invalid rates */
if (info->control.rates[i].idx < 0)
break;
- /* Rate masking supports only legacy rates for now */
- if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS)
- continue;
- rate_idx_match_mask(&info->control.rates[i],
- txrc->sband->n_bitrates, mask);
+ rate_idx_match_mask(&info->control.rates[i], txrc,
+ mask, mcs_mask);
}
}

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index e05667c..1be0ca2 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -635,6 +635,9 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
txrc.max_rate_idx = -1;
else
txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
+ memcpy(txrc.rate_idx_mcs_mask,
+ tx->sdata->rc_rateidx_mcs_mask[tx->channel->band],
+ sizeof(txrc.rate_idx_mcs_mask));
txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
tx->sdata->vif.type == NL80211_IFTYPE_ADHOC);
@@ -2431,6 +2434,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
txrc.max_rate_idx = -1;
else
txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
+ memcpy(txrc.rate_idx_mcs_mask, sdata->rc_rateidx_mcs_mask[band],
+ sizeof(txrc.rate_idx_mcs_mask));
txrc.bss = true;
rate_control_get_rate(sdata, NULL, &txrc);

--
1.7.8.3


2012-01-28 16:25:37

by Simon Wunderlich

[permalink] [raw]
Subject: [PATCH 1/2] iw: add nl80211 bitrates

Signed-off-by: Simon Wunderlich <[email protected]>
Signed-off-by: Mathias Kretschmer <[email protected]>
---
nl80211.h | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/nl80211.h b/nl80211.h
index a187606..445e0e4 100644
--- a/nl80211.h
+++ b/nl80211.h
@@ -2395,12 +2395,15 @@ enum nl80211_key_attributes {
* in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with
* 1 = 500 kbps) but without the IE length restriction (at most
* %NL80211_MAX_SUPP_RATES in a single array).
+ * @NL80211_TXRATE_MCS: HT (MCS) rates allowed for TX rate selection
+ * in an array of MCS numbers.
* @__NL80211_TXRATE_AFTER_LAST: internal
* @NL80211_TXRATE_MAX: highest TX rate attribute
*/
enum nl80211_tx_rate_attributes {
__NL80211_TXRATE_INVALID,
NL80211_TXRATE_LEGACY,
+ NL80211_TXRATE_MCS,

/* keep last */
__NL80211_TXRATE_AFTER_LAST,
--
1.7.7.3


2020-11-12 10:39:18

by Wen Gong

[permalink] [raw]
Subject: Re: [PATCHv3 1/2] nl80211: add support for mcs masks

On 2012-01-29 00:25, Simon Wunderlich wrote:
> Allow to set mcs masks through nl80211. We also allow to set MCS
> rates but no legacy rates (and vice versa).
>
> Signed-off-by: Simon Wunderlich <[email protected]>
> Signed-off-by: Mathias Kretschmer
> <[email protected]>
> ---
> include/linux/nl80211.h | 4 +++
> include/net/cfg80211.h | 3 +-
> net/wireless/nl80211.c | 61
> ++++++++++++++++++++++++++++++++++++++++++++++-
> 3 files changed, 65 insertions(+), 3 deletions(-)
>
...
> @@ -5421,12 +5451,20 @@ static int nl80211_set_tx_bitrate_mask(struct
> sk_buff *skb,
> sband = rdev->wiphy.bands[i];
> mask.control[i].legacy =
> sband ? (1 << sband->n_bitrates) - 1 : 0;
> + if (sband)
> + memcpy(mask.control[i].mcs,
> + sband->ht_cap.mcs.rx_mask,
> + sizeof(mask.control[i].mcs));
when use command: "iw wlan0 set bitrates legacy-5 6", I want to set it
fixed in 6M rate.
this copy mcs rate will add the mcs rate here and condition "if
(tb[NL80211_TXRATE_MCS])"
is false, then mcs rate will not clear and lead a mistake result.
> + else
> + memset(mask.control[i].mcs, 0,
> + sizeof(mask.control[i].mcs));
> }
>
> /*
> * The nested attribute uses enum nl80211_band as the index. This
> maps
> * directly to the enum ieee80211_band values used in cfg80211.
> */
> + BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN *
> 8);
> nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES],
> rem)
> {
> enum ieee80211_band band = nla_type(tx_rates);
> @@ -5442,7 +5480,28 @@ static int nl80211_set_tx_bitrate_mask(struct
> sk_buff *skb,
> sband,
> nla_data(tb[NL80211_TXRATE_LEGACY]),
> nla_len(tb[NL80211_TXRATE_LEGACY]));
> - if (mask.control[band].legacy == 0)
> + }
> + if (tb[NL80211_TXRATE_MCS]) {

false for "iw wlan0 set bitrates legacy-5 6", so ht_rateset_to_mask will
not enter and mcs rate will not clear.

> + if (!ht_rateset_to_mask(
> + sband,
> + nla_data(tb[NL80211_TXRATE_MCS]),
> + nla_len(tb[NL80211_TXRATE_MCS]),
> + mask.control[band].mcs))
> + return -EINVAL;
> + }
> +
> + if (mask.control[band].legacy == 0) {
> + /* don't allow empty legacy rates if HT
> + * is not even supported. */
> + if (!rdev->wiphy.bands[band]->ht_cap.ht_supported)
> + return -EINVAL;
> +
> + for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
> + if (mask.control[band].mcs[i])
> + break;
> +
> + /* legacy and mcs rates may not be both empty */
> + if (i == IEEE80211_HT_MCS_MASK_LEN)
> return -EINVAL;
> }
> }

2020-11-13 08:57:54

by Wen Gong

[permalink] [raw]
Subject: Re: [PATCHv3 1/2] nl80211: add support for mcs masks

On 2020-11-12 18:38, Wen Gong wrote:
> On 2012-01-29 00:25, Simon Wunderlich wrote:
>> Allow to set mcs masks through nl80211. We also allow to set MCS
>> rates but no legacy rates (and vice versa).
>>
>> Signed-off-by: Simon Wunderlich <[email protected]>
>> Signed-off-by: Mathias Kretschmer
>> <[email protected]>
>> ---
>> include/linux/nl80211.h | 4 +++
>> include/net/cfg80211.h | 3 +-
>> net/wireless/nl80211.c | 61
>> ++++++++++++++++++++++++++++++++++++++++++++++-
>> 3 files changed, 65 insertions(+), 3 deletions(-)
>>
> ...
>> @@ -5421,12 +5451,20 @@ static int nl80211_set_tx_bitrate_mask(struct
>> sk_buff *skb,
>> sband = rdev->wiphy.bands[i];
>> mask.control[i].legacy =
>> sband ? (1 << sband->n_bitrates) - 1 : 0;
>> + if (sband)
>> + memcpy(mask.control[i].mcs,
>> + sband->ht_cap.mcs.rx_mask,
>> + sizeof(mask.control[i].mcs));
> when use command: "iw wlan0 set bitrates legacy-5 6", I want to set it
> fixed in 6M rate.
> this copy mcs rate will add the mcs rate here and condition "if
> (tb[NL80211_TXRATE_MCS])"
> is false, then mcs rate will not clear and lead a mistake result.
>> + else
>> + memset(mask.control[i].mcs, 0,
>> + sizeof(mask.control[i].mcs));
>> }
>>
>> /*
>> * The nested attribute uses enum nl80211_band as the index. This
>> maps
>> * directly to the enum ieee80211_band values used in cfg80211.
>> */
>> + BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN *
>> 8);
>> nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES],
>> rem)
>> {
>> enum ieee80211_band band = nla_type(tx_rates);
>> @@ -5442,7 +5480,28 @@ static int nl80211_set_tx_bitrate_mask(struct
>> sk_buff *skb,
>> sband,
>> nla_data(tb[NL80211_TXRATE_LEGACY]),
>> nla_len(tb[NL80211_TXRATE_LEGACY]));
>> - if (mask.control[band].legacy == 0)
>> + }
>> + if (tb[NL80211_TXRATE_MCS]) {
>
> false for "iw wlan0 set bitrates legacy-5 6", so ht_rateset_to_mask
> will not enter and mcs rate will not clear.
If no tb[NL80211_TXRATE_HT]/tb[NL80211_TXRATE_VHT], it should clear the
data like this:
memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN) which is in ht_rateset_to_mask
and
memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX) which is in
vht_set_mcs_mask.
>
>> + if (!ht_rateset_to_mask(
>> + sband,
>> + nla_data(tb[NL80211_TXRATE_MCS]),
>> + nla_len(tb[NL80211_TXRATE_MCS]),
>> + mask.control[band].mcs))
>> + return -EINVAL;
>> + }
>> +
>> + if (mask.control[band].legacy == 0) {
>> + /* don't allow empty legacy rates if HT
>> + * is not even supported. */
>> + if (!rdev->wiphy.bands[band]->ht_cap.ht_supported)
>> + return -EINVAL;
>> +
>> + for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
>> + if (mask.control[band].mcs[i])
>> + break;
>> +
>> + /* legacy and mcs rates may not be both empty */
>> + if (i == IEEE80211_HT_MCS_MASK_LEN)
>> return -EINVAL;
>> }
>> }