2011-09-21 12:36:23

by Rajkumar Manoharan

[permalink] [raw]
Subject: [RFC 1/4] wireless: add new netlink attr to set tx rate for mgmt frame

This patch adds new nl80211 attribute that helps the user space
application to specify the rate for management frame transmission.

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
include/linux/nl80211.h | 4 ++++
net/wireless/nl80211.c | 1 +
2 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 460b12a..2666b23 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -919,6 +919,9 @@ enum nl80211_commands {
* rates based on negotiated supported rates information. This attribute
* is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
*
+ * @NL80211_ATTR_TX_MGMT_RATE: User requested rate that used to
+ * tranmit management frames
+ *
* @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
* at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME.
* @NL80211_ATTR_FRAME_TYPE: A u16 indicating the frame type/subtype for the
@@ -1222,6 +1225,7 @@ enum nl80211_attrs {
NL80211_ATTR_WIPHY_COVERAGE_CLASS,

NL80211_ATTR_TX_RATES,
+ NL80211_ATTR_TX_MGMT_RATE,

NL80211_ATTR_FRAME_MATCH,

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 3c6427a..a4ab044 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -164,6 +164,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_DURATION] = { .type = NLA_U32 },
[NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
[NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
+ [NL80211_ATTR_TX_MGMT_RATE] = { .type = NLA_U8 },
[NL80211_ATTR_FRAME] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
[NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
--
1.7.6.3



2011-09-21 12:36:38

by Rajkumar Manoharan

[permalink] [raw]
Subject: [RFC 3/4] mac80211: add support to tx rate of mgmt frames from userspace

This patch adds support to set the tx rate for management
frames when the rate was requested by user space apps and
the requested ratemask is stored in the skb's tx info.

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
include/net/mac80211.h | 3 +--
net/mac80211/cfg.c | 4 +++-
net/mac80211/tx.c | 2 ++
net/wireless/core.h | 3 ++-
net/wireless/mlme.c | 5 +++--
net/wireless/nl80211.c | 11 +++++++++--
6 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 9edba09..4f50614 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -518,8 +518,7 @@ struct ieee80211_tx_info {

u8 antenna_sel_tx;

- /* 2 byte hole */
- u8 pad[2];
+ u16 ratemask;

union {
struct {
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index b57ddf9..e00678d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1869,7 +1869,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait,
- const u8 *buf, size_t len, u64 *cookie)
+ const u8 *buf, size_t len, u32 ratemask,
+ u64 *cookie)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
@@ -1929,6 +1930,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
memcpy(skb_put(skb, len), buf, len);

IEEE80211_SKB_CB(skb)->flags = flags;
+ IEEE80211_SKB_CB(skb)->ratemask = ratemask;

skb->dev = sdata->dev;

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 217735d..c6c718f 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -630,6 +630,8 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
tx->sdata->local->scan_req &&
tx->sdata->local->scan_req->tx_ratemask)
txrc.rate_idx_mask = tx->sdata->local->scan_req->tx_ratemask;
+ else if (info->ratemask)
+ txrc.rate_idx_mask = info->ratemask;
else
txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask
[tx->channel->band];
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 796a4bd..eff7c1c 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -375,7 +375,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait,
- const u8 *buf, size_t len, u64 *cookie);
+ const u8 *buf, size_t len, u32 ratemask,
+ u64 *cookie);

/* SME */
int __cfg80211_connect(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 61adea5..2074270 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -900,7 +900,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait,
- const u8 *buf, size_t len, u64 *cookie)
+ const u8 *buf, size_t len, u32 ratemask,
+ u64 *cookie)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
const struct ieee80211_mgmt *mgmt;
@@ -991,7 +992,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
/* Transmit the Action frame as requested by user space */
return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan,
channel_type, channel_type_valid,
- wait, buf, len, cookie);
+ wait, buf, len, ratemask, cookie);
}

bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ce42efb..ce4e3af 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5190,7 +5190,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
struct ieee80211_channel *chan;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
bool channel_type_valid = false;
- u32 freq;
+ u32 freq, ratemask = 0;
int err;
void *hdr;
u64 cookie;
@@ -5233,6 +5233,13 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)

offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];

+ if (info->attrs[NL80211_ATTR_TX_MGMT_RATE]) {
+ u8 rate = nla_get_u8(info->attrs[NL80211_ATTR_TX_MGMT_RATE]);
+ ratemask = rateset_to_mask(
+ rdev->wiphy.bands[IEEE80211_BAND_2GHZ],
+ &rate, 1);
+ }
+
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
chan = rdev_freq_to_chan(rdev, freq, channel_type);
if (chan == NULL)
@@ -5253,7 +5260,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
channel_type_valid, wait,
nla_data(info->attrs[NL80211_ATTR_FRAME]),
nla_len(info->attrs[NL80211_ATTR_FRAME]),
- &cookie);
+ ratemask, &cookie);
if (err)
goto free_msg;

--
1.7.6.3


2011-09-21 12:36:45

by Rajkumar Manoharan

[permalink] [raw]
Subject: [RFC 4/4] mac80211: set the request rate as lowest on for mgmt frames

Currently the ath9k/minstral rate control sets the least
supported rate as first rate for all management frames.
This patch set the requested rate as first rate that was
derived either from scan request or from the tx info.

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
net/mac80211/rate.c | 69 ++++++++++++++++++++++++++++----------------------
1 files changed, 39 insertions(+), 30 deletions(-)

diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 3d5a2cb..232acd5 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -233,36 +233,6 @@ static void rc_send_low_broadcast(s8 *idx, u32 basic_rates,
/* could not find a basic rate; use original selection */
}

-bool rate_control_send_low(struct ieee80211_sta *sta,
- void *priv_sta,
- struct ieee80211_tx_rate_control *txrc)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
- struct ieee80211_supported_band *sband = txrc->sband;
- int mcast_rate;
-
- if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) {
- info->control.rates[0].idx = rate_lowest_index(txrc->sband, sta);
- info->control.rates[0].count =
- (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
- 1 : txrc->hw->max_rate_tries;
- if (!sta && txrc->bss) {
- mcast_rate = txrc->bss_conf->mcast_rate[sband->band];
- if (mcast_rate > 0) {
- info->control.rates[0].idx = mcast_rate - 1;
- return true;
- }
-
- rc_send_low_broadcast(&info->control.rates[0].idx,
- txrc->bss_conf->basic_rates,
- sband);
- }
- return true;
- }
- return false;
-}
-EXPORT_SYMBOL(rate_control_send_low);
-
static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
int n_bitrates, u32 mask)
{
@@ -295,6 +265,45 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
*/
}

+bool rate_control_send_low(struct ieee80211_sta *sta,
+ void *priv_sta,
+ struct ieee80211_tx_rate_control *txrc)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
+ struct ieee80211_supported_band *sband = txrc->sband;
+ int mcast_rate;
+
+ if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) {
+ if (txrc->max_rate_idx != -1) {
+ rate_idx_match_mask(&info->control.rates[0],
+ txrc->sband->n_bitrates,
+ txrc->rate_idx_mask);
+ if (info->control.rates[0].idx == -1)
+ txrc->max_rate_idx = -1;
+ }
+ if (txrc->max_rate_idx == -1)
+ info->control.rates[0].idx =
+ rate_lowest_index(txrc->sband, sta);
+ info->control.rates[0].count =
+ (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
+ 1 : txrc->hw->max_rate_tries;
+ if (!sta && txrc->bss) {
+ mcast_rate = txrc->bss_conf->mcast_rate[sband->band];
+ if (mcast_rate > 0) {
+ info->control.rates[0].idx = mcast_rate - 1;
+ return true;
+ }
+
+ rc_send_low_broadcast(&info->control.rates[0].idx,
+ txrc->bss_conf->basic_rates,
+ sband);
+ }
+ return true;
+ }
+ return false;
+}
+EXPORT_SYMBOL(rate_control_send_low);
+
void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct ieee80211_tx_rate_control *txrc)
--
1.7.6.3


2011-09-21 12:36:30

by Rajkumar Manoharan

[permalink] [raw]
Subject: [RFC 2/4] mac80211: add tx_ratemask support to scan request

Set the requested rate for probe request sent during the scan.
In this way, we can restrict the 11b rates not to be used
for the p2p probes before the p2p group is formed.

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
include/net/cfg80211.h | 4 ++-
net/mac80211/tx.c | 8 ++++++-
net/wireless/nl80211.c | 55 +++++++++++++++++++++++++++---------------------
3 files changed, 41 insertions(+), 26 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ccfdf3f..425a8d2 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -860,6 +860,7 @@ struct cfg80211_ssid {
* @wiphy: the wiphy this was for
* @dev: the interface
* @aborted: (internal) scan request was notified as aborted
+ * @tx_ratemask: (internal) used to send probe request at the given rate
*/
struct cfg80211_scan_request {
struct cfg80211_ssid *ssids;
@@ -874,6 +875,7 @@ struct cfg80211_scan_request {
struct wiphy *wiphy;
struct net_device *dev;
bool aborted;
+ u32 tx_ratemask;

/* keep last */
struct ieee80211_channel *channels[0];
@@ -1560,7 +1562,7 @@ struct cfg80211_ops {
struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait,
- const u8 *buf, size_t len, u64 *cookie);
+ const u8 *buf, size_t len, u32 ratemask, u64 *cookie);
int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
struct net_device *dev,
u64 cookie);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 7cd6c28..217735d 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -626,7 +626,13 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
txrc.bss_conf = &tx->sdata->vif.bss_conf;
txrc.skb = tx->skb;
txrc.reported_rate.idx = -1;
- txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[tx->channel->band];
+ if (ieee80211_is_probe_req(hdr->frame_control) &&
+ tx->sdata->local->scan_req &&
+ tx->sdata->local->scan_req->tx_ratemask)
+ txrc.rate_idx_mask = tx->sdata->local->scan_req->tx_ratemask;
+ else
+ txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask
+ [tx->channel->band];
if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1)
txrc.max_rate_idx = -1;
else
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a4ab044..ce42efb 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3461,6 +3461,30 @@ static int validate_scan_freqs(struct nlattr *freqs)
return n_channels;
}

+static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
+ u8 *rates, u8 rates_len)
+{
+ u8 i;
+ u32 mask = 0;
+
+ for (i = 0; i < rates_len; i++) {
+ int rate = (rates[i] & 0x7f) * 5;
+ int ridx;
+ for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
+ struct ieee80211_rate *srate =
+ &sband->bitrates[ridx];
+ if (rate == srate->bitrate) {
+ mask |= 1 << ridx;
+ break;
+ }
+ }
+ if (ridx == sband->n_bitrates)
+ return 0; /* rate not found */
+ }
+
+ return mask;
+}
+
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -3621,6 +3645,13 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
}
}

+ if (info->attrs[NL80211_ATTR_TX_MGMT_RATE]) {
+ u8 rate = nla_get_u8(info->attrs[NL80211_ATTR_TX_MGMT_RATE]);
+ request->tx_ratemask = rateset_to_mask(
+ rdev->wiphy.bands[IEEE80211_BAND_2GHZ],
+ &rate, 1);
+ }
+
request->dev = dev;
request->wiphy = &rdev->wiphy;

@@ -5064,30 +5095,6 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie);
}

-static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
- u8 *rates, u8 rates_len)
-{
- u8 i;
- u32 mask = 0;
-
- for (i = 0; i < rates_len; i++) {
- int rate = (rates[i] & 0x7f) * 5;
- int ridx;
- for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
- struct ieee80211_rate *srate =
- &sband->bitrates[ridx];
- if (rate == srate->bitrate) {
- mask |= 1 << ridx;
- break;
- }
- }
- if (ridx == sband->n_bitrates)
- return 0; /* rate not found */
- }
-
- return mask;
-}
-
static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
[NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
.len = NL80211_MAX_SUPP_RATES },
--
1.7.6.3