Skip to content

Commit

Permalink
nl80211: add support for mcs masks
Browse files Browse the repository at this point in the history
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 <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Simon Wunderlich authored and John W. Linville committed Jan 30, 2012
1 parent d273bb2 commit 24db78c
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 3 deletions.
4 changes: 4 additions & 0 deletions include/linux/nl80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 1 addition & 2 deletions include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];
};
/**
Expand Down
61 changes: 60 additions & 1 deletion net/wireless/nl80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
Expand All @@ -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;
}
}
Expand Down

0 comments on commit 24db78c

Please sign in to comment.