2012-11-09 20:16:59

by Johannes Berg

[permalink] [raw]
Subject: VHT support, take 2

Hi,

Here's a new version of the VHT patches, in case you're bored
over the weekend and want some exciting code to read! ;-)

I do need to test these, I had tested the previous set but not
after the mac80211 rework yet.

However, at this point I'm more interested in seeing whether
you all think this is sane at all or if I'm on crack?

What I intend to do next is this have a patch to parse the VHT
operation IE in mac80211 (or have a helper in cfg80211?) to
select the VHT channel configuration in MLME code.

I'm kinda hoping the posedge folks will come back with the
regulatory code so I don't have to worry about that ...
*hint hint* :-)

After that, I'll need to work on the remaining hostapd code,
that should just need channel configuration etc. now. Then I
think it just needs a good test run.

I'm not interested in VHT IBSS, so I'm not going to do anything
there, nor VHT mesh.

The other thing would be rate control, e.g. minstrel_vht, but
I'm not sure we can use minstrel at all, so I'll probalby not
work on minstrel myself.

johannes



2012-11-20 12:21:14

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

On Tue, 2012-11-20 at 17:29 +0530, Mahesh Palivela wrote:

> >>> For loops in both functions seems to be similar. One return false, other
> >>> return -EINVAL. Can we remove duplication?
> >>
> >> True, but they check different flags. I suppose we could have a common
> >> function where the checked flags are passed in, I can try that.
> >
> > I'll add this to the patch:
> >
> > http://p.sipsolutions.net/24eb25fb98ef2d0b.txt
> >
>
> Looks good to me Johannes. Overall your VHT channel config
> implementation done so well.

Thanks for reviewing!

> Partial regulatory check in nl80211_parse_chandef() has to be modified
> to include BW check. I see your TODO comment there.

Yes, although I'm not completely sure the bandwidth check ever made
sense? We'll need to discuss that.

Regardless of that though, I'm tempted to put this into the tree now. As
we don't have any drivers (but hwsim) using it, we won't have any
regulatory issues without the bandwidth check for now, and then we can
base further work on this.

Any objections from you? If not I'll repost the whole thing as [PATCH].

johannes


2012-11-20 08:27:20

by Mahesh Palivela

[permalink] [raw]
Subject: Re: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

On 11/10/2012 01:47 AM, Johannes Berg wrote:
> From: Johannes Berg <[email protected]>

> diff --git a/net/wireless/chan.c b/net/wireless/chan.c

> +static bool cfg80211_check_beacon_chans(struct wiphy *wiphy,
> + u32 center_freq, u32 bw)
> +{
> + struct ieee80211_channel *c;
> + u32 freq;
> +
> + for (freq = center_freq - bw/2 + 10;
> + freq <= center_freq + bw/2 - 10;
> + freq += 20) {
> + c = ieee80211_get_channel(wiphy, freq);
> + if (!c || c->flags & (IEEE80211_CHAN_DISABLED |
> + IEEE80211_CHAN_PASSIVE_SCAN |
> + IEEE80211_CHAN_NO_IBSS |
> + IEEE80211_CHAN_RADAR))
> + return false;
> }
>
> - sec_chan = ieee80211_get_channel(wiphy,
> - chandef->chan->center_freq + diff);
> - if (!sec_chan) {
> + return true;
> +}

> diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c

> +static int nl80211_check_sec_chans(struct cfg80211_registered_device *rdev,
> + u32 center_freq, u32 bw)
> {
> - enum nl80211_channel_type tmp;
> -
> - if (!info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
> - return false;
> + struct ieee80211_channel *c;
> + u32 freq;
>
> - tmp = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
> - if (tmp != NL80211_CHAN_NO_HT &&
> - tmp != NL80211_CHAN_HT20 &&
> - tmp != NL80211_CHAN_HT40PLUS &&
> - tmp != NL80211_CHAN_HT40MINUS)
> - return false;
> -
> - if (channel_type)
> - *channel_type = tmp;
> + for (freq = center_freq - bw/2 + 10;
> + freq <= center_freq + bw/2 - 10;
> + freq += 20) {
> + c = ieee80211_get_channel(&rdev->wiphy, freq);
> + if (!c || c->flags & IEEE80211_CHAN_DISABLED)
> + return -EINVAL;
> + }
>
> - return true;
> + return 0;
> }

For loops in both functions seems to be similar. One return false, other
return -EINVAL. Can we remove duplication?

2012-11-09 20:17:00

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2 1/8] cfg80211: remove remain-on-channel channel type

From: Johannes Berg <[email protected]>

As mwifiex (and mac80211 in the software case) are the
only drivers actually implementing remain-on-channel
with channel type, userspace can't be relying on it.
This is the case, as it's used only for P2P operations
right now.

Rather than adding a flag to tell userspace whether or
not it can actually rely on it, simplify all the code
by removing the ability to use different channel types.
Leave only the validation of the attribute, so that if
we extend it again later (with the needed capability
flag), it can't break userspace sending invalid data.

Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 7 ++--
drivers/net/wireless/ath/ath6kl/wmi.c | 5 ++-
drivers/net/wireless/iwlwifi/dvm/dev.h | 1 -
drivers/net/wireless/iwlwifi/dvm/mac80211.c | 2 --
drivers/net/wireless/mac80211_hwsim.c | 1 -
drivers/net/wireless/mwifiex/cfg80211.c | 16 +++------
drivers/net/wireless/mwifiex/main.h | 2 --
drivers/net/wireless/mwifiex/sta_event.c | 1 -
drivers/net/wireless/mwifiex/sta_ioctl.c | 3 +-
include/net/cfg80211.h | 11 ++----
include/net/mac80211.h | 1 -
include/uapi/linux/nl80211.h | 14 ++++----
net/mac80211/cfg.c | 25 +++++---------
net/mac80211/driver-ops.h | 6 ++--
net/mac80211/ieee80211_i.h | 2 --
net/mac80211/main.c | 2 +-
net/mac80211/offchannel.c | 11 +++---
net/mac80211/trace.h | 6 ++--
net/wireless/core.h | 6 ++--
net/wireless/mlme.c | 21 ++++--------
net/wireless/nl80211.c | 36 ++++++++------------
net/wireless/nl80211.h | 4 +--
net/wireless/rdev-ops.h | 20 +++++------
net/wireless/trace.h | 52 ++++++++++-------------------
24 files changed, 82 insertions(+), 173 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index d615f9f..74091d3 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -2976,7 +2976,6 @@ static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
static int ath6kl_remain_on_channel(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
unsigned int duration,
u64 *cookie)
{
@@ -3135,10 +3134,8 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)

static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
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, bool no_cck,
- bool dont_wait_for_ack, u64 *cookie)
+ unsigned int wait, const u8 *buf, size_t len,
+ bool no_cck, bool dont_wait_for_ack, u64 *cookie)
{
struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
struct ath6kl *ar = ath6kl_priv(vif->ndev);
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index c30ab4b..0e05c41 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -474,7 +474,7 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap,
return -EINVAL;
}
id = vif->last_roc_id;
- cfg80211_ready_on_channel(&vif->wdev, id, chan, NL80211_CHAN_NO_HT,
+ cfg80211_ready_on_channel(&vif->wdev, id, chan,
dur, GFP_ATOMIC);

return 0;
@@ -513,8 +513,7 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,
else
id = vif->last_roc_id; /* timeout on uncanceled r-o-c */
vif->last_cancel_roc_id = 0;
- cfg80211_remain_on_channel_expired(&vif->wdev, id, chan,
- NL80211_CHAN_NO_HT, GFP_ATOMIC);
+ cfg80211_remain_on_channel_expired(&vif->wdev, id, chan, GFP_ATOMIC);

return 0;
}
diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h
index 8141f91..29c571a 100644
--- a/drivers/net/wireless/iwlwifi/dvm/dev.h
+++ b/drivers/net/wireless/iwlwifi/dvm/dev.h
@@ -789,7 +789,6 @@ struct iwl_priv {
/* remain-on-channel offload support */
struct ieee80211_channel *hw_roc_channel;
struct delayed_work hw_roc_disable_work;
- enum nl80211_channel_type hw_roc_chantype;
int hw_roc_duration;
bool hw_roc_setup, hw_roc_start_notified;

diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index ff8162d..f0d7620 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -1033,7 +1033,6 @@ done:

static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type,
int duration)
{
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
@@ -1065,7 +1064,6 @@ static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
}

priv->hw_roc_channel = channel;
- priv->hw_roc_chantype = channel_type;
/* convert from ms to TU */
priv->hw_roc_duration = DIV_ROUND_UP(1000 * duration, 1024);
priv->hw_roc_start_notified = false;
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index a8ec708..7ef42c6 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1423,7 +1423,6 @@ static void hw_roc_done(struct work_struct *work)

static int mac80211_hwsim_roc(struct ieee80211_hw *hw,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
int duration)
{
struct mac80211_hwsim_data *hwsim = hw->priv;
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 8e829b2..f69190b 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -180,10 +180,8 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len)
static int
mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
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, bool no_cck,
- bool dont_wait_for_ack, u64 *cookie)
+ unsigned int wait, const u8 *buf, size_t len,
+ bool no_cck, bool dont_wait_for_ack, u64 *cookie)
{
struct sk_buff *skb;
u16 pkt_len;
@@ -253,7 +251,6 @@ static int
mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
unsigned int duration, u64 *cookie)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
@@ -271,15 +268,14 @@ mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy,
}

ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_SET, chan,
- &channel_type, duration);
+ duration);

if (!ret) {
*cookie = random32() | 1;
priv->roc_cfg.cookie = *cookie;
priv->roc_cfg.chan = *chan;
- priv->roc_cfg.chan_type = channel_type;

- cfg80211_ready_on_channel(wdev, *cookie, chan, channel_type,
+ cfg80211_ready_on_channel(wdev, *cookie, chan,
duration, GFP_ATOMIC);

wiphy_dbg(wiphy, "info: ROC, cookie = 0x%llx\n", *cookie);
@@ -302,13 +298,11 @@ mwifiex_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
return -ENOENT;

ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_REMOVE,
- &priv->roc_cfg.chan,
- &priv->roc_cfg.chan_type, 0);
+ &priv->roc_cfg.chan, 0);

if (!ret) {
cfg80211_remain_on_channel_expired(wdev, cookie,
&priv->roc_cfg.chan,
- priv->roc_cfg.chan_type,
GFP_ATOMIC);

memset(&priv->roc_cfg, 0, sizeof(struct mwifiex_roc_cfg));
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 81f8772..771717d 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -371,7 +371,6 @@ struct wps {
struct mwifiex_roc_cfg {
u64 cookie;
struct ieee80211_channel chan;
- enum nl80211_channel_type chan_type;
};

struct mwifiex_adapter;
@@ -1016,7 +1015,6 @@ int mwifiex_get_ver_ext(struct mwifiex_private *priv);

int mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
struct ieee80211_channel *chan,
- enum nl80211_channel_type *channel_type,
unsigned int duration);

int mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role);
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index 8132119..78dfa31 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -424,7 +424,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
cfg80211_remain_on_channel_expired(priv->wdev,
priv->roc_cfg.cookie,
&priv->roc_cfg.chan,
- priv->roc_cfg.chan_type,
GFP_ATOMIC);

memset(&priv->roc_cfg, 0x00, sizeof(struct mwifiex_roc_cfg));
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 552d72e..24af6ba 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -1046,7 +1046,6 @@ mwifiex_get_ver_ext(struct mwifiex_private *priv)
int
mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
struct ieee80211_channel *chan,
- enum nl80211_channel_type *ct,
unsigned int duration)
{
struct host_cmd_ds_remain_on_chan roc_cfg;
@@ -1056,7 +1055,7 @@ mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
roc_cfg.action = cpu_to_le16(action);
if (action == HostCmd_ACT_GEN_SET) {
roc_cfg.band_cfg = chan->band;
- sc = mwifiex_chan_type_to_sec_chan_offset(*ct);
+ sc = mwifiex_chan_type_to_sec_chan_offset(NL80211_CHAN_NO_HT);
roc_cfg.band_cfg |= (sc << 2);

roc_cfg.channel =
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index b57337d..9de217e 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1791,7 +1791,6 @@ struct cfg80211_ops {
int (*remain_on_channel)(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
unsigned int duration,
u64 *cookie);
int (*cancel_remain_on_channel)(struct wiphy *wiphy,
@@ -1800,10 +1799,8 @@ struct cfg80211_ops {

int (*mgmt_tx)(struct wiphy *wiphy, struct wireless_dev *wdev,
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, bool no_cck,
- bool dont_wait_for_ack, u64 *cookie);
+ unsigned int wait, const u8 *buf, size_t len,
+ bool no_cck, bool dont_wait_for_ack, u64 *cookie);
int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
struct wireless_dev *wdev,
u64 cookie);
@@ -3350,14 +3347,12 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
* @wdev: wireless device
* @cookie: the request cookie
* @chan: The current channel (from remain_on_channel request)
- * @channel_type: Channel type
* @duration: Duration in milliseconds that the driver intents to remain on the
* channel
* @gfp: allocation flags
*/
void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp);

/**
@@ -3365,12 +3360,10 @@ void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
* @wdev: wireless device
* @cookie: the request cookie
* @chan: The current channel (from remain_on_channel request)
- * @channel_type: Channel type
* @gfp: allocation flags
*/
void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
gfp_t gfp);


diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index a789dd1..bdb8f4f 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2515,7 +2515,6 @@ struct ieee80211_ops {

int (*remain_on_channel)(struct ieee80211_hw *hw,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
int duration);
int (*cancel_remain_on_channel)(struct ieee80211_hw *hw);
int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx);
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index f689df1..d33d780 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -401,8 +401,7 @@
* a response while being associated to an AP on another channel.
* %NL80211_ATTR_IFINDEX is used to specify which interface (and thus
* radio) is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
- * frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be
- * optionally used to specify additional channel parameters.
+ * frequency for the operation.
* %NL80211_ATTR_DURATION is used to specify the duration in milliseconds
* to remain on the channel. This command is also used as an event to
* notify when the requested duration starts (it may take a while for the
@@ -440,12 +439,11 @@
* as an event indicating reception of a frame that was not processed in
* kernel code, but is for us (i.e., which may need to be processed in a
* user space application). %NL80211_ATTR_FRAME is used to specify the
- * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and
- * optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on
- * which channel the frame is to be transmitted or was received. If this
- * channel is not the current channel (remain-on-channel or the
- * operational channel) the device will switch to the given channel and
- * transmit the frame, optionally waiting for a response for the time
+ * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ is used
+ * to indicate on which channel the frame is to be transmitted or was
+ * received. If this channel is not the current channel (remain-on-channel
+ * or the operational channel) the device will switch to the given channel
+ * and transmit the frame, optionally waiting for a response for the time
* specified using %NL80211_ATTR_DURATION. When called, this operation
* returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the
* TX status event pertaining to the TX request.
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a9a8072..63f55d8 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2263,7 +2263,6 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
static int ieee80211_start_roc_work(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type,
unsigned int duration, u64 *cookie,
struct sk_buff *txskb)
{
@@ -2281,7 +2280,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
return -ENOMEM;

roc->chan = channel;
- roc->chan_type = channel_type;
roc->duration = duration;
roc->req_duration = duration;
roc->frame = txskb;
@@ -2314,7 +2312,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
if (!duration)
duration = 10;

- ret = drv_remain_on_channel(local, channel, channel_type, duration);
+ ret = drv_remain_on_channel(local, channel, duration);
if (ret) {
kfree(roc);
return ret;
@@ -2325,7 +2323,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,

out_check_combine:
list_for_each_entry(tmp, &local->roc_list, list) {
- if (tmp->chan != channel || tmp->chan_type != channel_type)
+ if (tmp->chan != channel)
continue;

/*
@@ -2442,7 +2440,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
static int ieee80211_remain_on_channel(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
unsigned int duration,
u64 *cookie)
{
@@ -2451,7 +2448,7 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy,
int ret;

mutex_lock(&local->mtx);
- ret = ieee80211_start_roc_work(local, sdata, chan, channel_type,
+ ret = ieee80211_start_roc_work(local, sdata, chan,
duration, cookie, NULL);
mutex_unlock(&local->mtx);

@@ -2544,10 +2541,8 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,

static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
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, bool no_cck,
- bool dont_wait_for_ack, u64 *cookie)
+ unsigned int wait, const u8 *buf, size_t len,
+ bool no_cck, bool dont_wait_for_ack, u64 *cookie)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct ieee80211_local *local = sdata->local;
@@ -2616,14 +2611,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);

- if (chanctx_conf) {
+ if (chanctx_conf)
need_offchan = chan != chanctx_conf->channel;
- if (channel_type_valid &&
- channel_type != chanctx_conf->channel_type)
- need_offchan = true;
- } else {
+ else
need_offchan = true;
- }
rcu_read_unlock();
}

@@ -2658,7 +2649,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
local->hw.offchannel_tx_hw_queue;

/* This will handle all kinds of coalescing and immediate TX */
- ret = ieee80211_start_roc_work(local, sdata, chan, channel_type,
+ ret = ieee80211_start_roc_work(local, sdata, chan,
wait, cookie, skb);
if (ret)
kfree_skb(skb);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 4dc2577..48da70c 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -705,16 +705,14 @@ static inline int drv_get_antenna(struct ieee80211_local *local,

static inline int drv_remain_on_channel(struct ieee80211_local *local,
struct ieee80211_channel *chan,
- enum nl80211_channel_type chantype,
unsigned int duration)
{
int ret;

might_sleep();

- trace_drv_remain_on_channel(local, chan, chantype, duration);
- ret = local->ops->remain_on_channel(&local->hw, chan, chantype,
- duration);
+ trace_drv_remain_on_channel(local, chan, duration);
+ ret = local->ops->remain_on_channel(&local->hw, chan, duration);
trace_drv_return_int(local, ret);

return ret;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 904b4d8..6f747cf 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -348,7 +348,6 @@ struct ieee80211_roc_work {
struct ieee80211_sub_if_data *sdata;

struct ieee80211_channel *chan;
- enum nl80211_channel_type chan_type;

bool started, abort, hw_begun, notified;

@@ -1048,7 +1047,6 @@ struct ieee80211_local {

/* Temporary remain-on-channel for off-channel operations */
struct ieee80211_channel *tmp_channel;
- enum nl80211_channel_type tmp_channel_type;

/* channel contexts */
struct list_head chanctx_list;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 827ed9ad..cd88a4b 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -115,7 +115,7 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
channel_type = NL80211_CHAN_NO_HT;
} else if (local->tmp_channel) {
chan = local->tmp_channel;
- channel_type = local->tmp_channel_type;
+ channel_type = NL80211_CHAN_NO_HT;
} else {
chan = local->_oper_channel;
channel_type = local->_oper_channel_type;
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 0cd42d5..b26a820 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -205,8 +205,8 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)
}
} else {
cfg80211_ready_on_channel(&roc->sdata->wdev, roc->cookie,
- roc->chan, roc->chan_type,
- roc->req_duration, GFP_KERNEL);
+ roc->chan, roc->req_duration,
+ GFP_KERNEL);
}

roc->notified = true;
@@ -283,9 +283,7 @@ void ieee80211_start_next_roc(struct ieee80211_local *local)
if (!duration)
duration = 10;

- ret = drv_remain_on_channel(local, roc->chan,
- roc->chan_type,
- duration);
+ ret = drv_remain_on_channel(local, roc->chan, duration);

roc->started = true;

@@ -321,7 +319,7 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
if (!roc->mgmt_tx_cookie)
cfg80211_remain_on_channel_expired(&roc->sdata->wdev,
roc->cookie, roc->chan,
- roc->chan_type, GFP_KERNEL);
+ GFP_KERNEL);

list_for_each_entry_safe(dep, tmp, &roc->dependents, list)
ieee80211_roc_notify_destroy(dep);
@@ -359,7 +357,6 @@ void ieee80211_sw_roc_work(struct work_struct *work)
ieee80211_recalc_idle(local);

local->tmp_channel = roc->chan;
- local->tmp_channel_type = roc->chan_type;
ieee80211_hw_config(local, 0);

/* tell userspace or send frame */
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 758836c..1b86d60 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -1020,21 +1020,19 @@ TRACE_EVENT(drv_get_antenna,

TRACE_EVENT(drv_remain_on_channel,
TP_PROTO(struct ieee80211_local *local, struct ieee80211_channel *chan,
- enum nl80211_channel_type chantype, unsigned int duration),
+ unsigned int duration),

- TP_ARGS(local, chan, chantype, duration),
+ TP_ARGS(local, chan, duration),

TP_STRUCT__entry(
LOCAL_ENTRY
__field(int, center_freq)
- __field(int, channel_type)
__field(unsigned int, duration)
),

TP_fast_assign(
LOCAL_ASSIGN;
__entry->center_freq = chan->center_freq;
- __entry->channel_type = chantype;
__entry->duration = duration;
),

diff --git a/net/wireless/core.h b/net/wireless/core.h
index e53831c..b0a09cf 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -378,10 +378,8 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
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, bool no_cck,
- bool dont_wait_for_ack, u64 *cookie);
+ unsigned int wait, const u8 *buf, size_t len,
+ bool no_cck, bool dont_wait_for_ack, u64 *cookie);
void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
const struct ieee80211_ht_cap *ht_capa_mask);

diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 4bfd14f..a9646b5 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -579,31 +579,25 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,

void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp)
{
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);

- trace_cfg80211_ready_on_channel(wdev, cookie, chan, channel_type,
- duration);
- nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, channel_type,
- duration, gfp);
+ trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
+ nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, duration, gfp);
}
EXPORT_SYMBOL(cfg80211_ready_on_channel);

void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
gfp_t gfp)
{
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);

- trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan,
- channel_type);
- nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan,
- channel_type, gfp);
+ trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
+ nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan, gfp);
}
EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);

@@ -758,10 +752,8 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
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, bool no_cck,
- bool dont_wait_for_ack, u64 *cookie)
+ unsigned int wait, const u8 *buf, size_t len,
+ bool no_cck, bool dont_wait_for_ack, u64 *cookie)
{
const struct ieee80211_mgmt *mgmt;
u16 stype;
@@ -855,7 +847,6 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,

/* Transmit the Action frame as requested by user space */
return rdev_mgmt_tx(rdev, wdev, chan, offchan,
- channel_type, channel_type_valid,
wait, buf, len, no_cck, dont_wait_for_ack,
cookie);
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e4b205e..7db26b6 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5976,7 +5976,6 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
struct sk_buff *msg;
void *hdr;
u64 cookie;
- enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
u32 freq, duration;
int err;

@@ -5999,11 +5998,11 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
return -EINVAL;

if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
- !nl80211_valid_channel_type(info, &channel_type))
+ !nl80211_valid_channel_type(info, NULL))
return -EINVAL;

freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
- chan = rdev_freq_to_chan(rdev, freq, channel_type);
+ chan = rdev_freq_to_chan(rdev, freq, NL80211_CHAN_NO_HT);
if (chan == NULL)
return -EINVAL;

@@ -6019,8 +6018,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
goto free_msg;
}

- err = rdev_remain_on_channel(rdev, wdev, chan, channel_type, duration,
- &cookie);
+ err = rdev_remain_on_channel(rdev, wdev, chan, duration, &cookie);

if (err)
goto free_msg;
@@ -6240,8 +6238,6 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct wireless_dev *wdev = info->user_ptr[1];
struct ieee80211_channel *chan;
- enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
- bool channel_type_valid = false;
u32 freq;
int err;
void *hdr = NULL;
@@ -6288,11 +6284,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)

}

- if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
- if (!nl80211_valid_channel_type(info, &channel_type))
- return -EINVAL;
- channel_type_valid = true;
- }
+ if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
+ !nl80211_valid_channel_type(info, NULL))
+ return -EINVAL;

offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];

@@ -6302,7 +6296,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);

freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
- chan = rdev_freq_to_chan(rdev, freq, channel_type);
+ chan = rdev_freq_to_chan(rdev, freq, NL80211_CHAN_NO_HT);
if (chan == NULL)
return -EINVAL;

@@ -6320,8 +6314,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
}
}

- err = cfg80211_mlme_mgmt_tx(rdev, wdev, chan, offchan, channel_type,
- channel_type_valid, wait,
+ err = cfg80211_mlme_mgmt_tx(rdev, wdev, chan, offchan, wait,
nla_data(info->attrs[NL80211_ATTR_FRAME]),
nla_len(info->attrs[NL80211_ATTR_FRAME]),
no_cck, dont_wait_for_ack, &cookie);
@@ -8419,7 +8412,6 @@ static void nl80211_send_remain_on_chan_event(
int cmd, struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp)
{
struct sk_buff *msg;
@@ -8440,7 +8432,8 @@ static void nl80211_send_remain_on_chan_event(
wdev->netdev->ifindex)) ||
nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
- nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ NL80211_CHAN_NO_HT) ||
nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie))
goto nla_put_failure;

@@ -8462,23 +8455,20 @@ static void nl80211_send_remain_on_chan_event(
void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp)
{
nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
rdev, wdev, cookie, chan,
- channel_type, duration, gfp);
+ duration, gfp);
}

void nl80211_send_remain_on_channel_cancel(
struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
- u64 cookie, struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type, gfp_t gfp)
+ u64 cookie, struct ieee80211_channel *chan, gfp_t gfp)
{
nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
- rdev, wdev, cookie, chan,
- channel_type, 0, gfp);
+ rdev, wdev, cookie, chan, 0, gfp);
}

void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index f615351..7adbd76 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -76,13 +76,11 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp);
void nl80211_send_remain_on_channel_cancel(
struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
- u64 cookie, struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type, gfp_t gfp);
+ u64 cookie, struct ieee80211_channel *chan, gfp_t gfp);

void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *mac_addr,
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 6e5fa65..ee54a5a 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -600,14 +600,12 @@ static inline int
rdev_remain_on_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
unsigned int duration, u64 *cookie)
{
int ret;
- trace_rdev_remain_on_channel(&rdev->wiphy, wdev, chan, channel_type,
- duration);
+ trace_rdev_remain_on_channel(&rdev->wiphy, wdev, chan, duration);
ret = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan,
- channel_type, duration, cookie);
+ duration, cookie);
trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
return ret;
}
@@ -626,17 +624,15 @@ rdev_cancel_remain_on_channel(struct cfg80211_registered_device *rdev,
static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
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, bool no_cck,
- bool dont_wait_for_ack, u64 *cookie)
+ unsigned int wait, const u8 *buf, size_t len,
+ bool no_cck, bool dont_wait_for_ack, u64 *cookie)
{
int ret;
- trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan, channel_type,
- channel_type_valid, wait, no_cck, dont_wait_for_ack);
+ trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
+ wait, no_cck, dont_wait_for_ack);
ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
- channel_type, channel_type_valid, wait, buf,
- len, no_cck, dont_wait_for_ack, cookie);
+ wait, buf, len, no_cck,
+ dont_wait_for_ack, cookie);
trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
return ret;
}
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 8e03c63..0128307 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1573,25 +1573,22 @@ DEFINE_EVENT(rdev_pmksa, rdev_del_pmksa,
TRACE_EVENT(rdev_remain_on_channel,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type, unsigned int duration),
- TP_ARGS(wiphy, wdev, chan, channel_type, duration),
+ unsigned int duration),
+ TP_ARGS(wiphy, wdev, chan, duration),
TP_STRUCT__entry(
WIPHY_ENTRY
WDEV_ENTRY
CHAN_ENTRY
- __field(enum nl80211_channel_type, channel_type)
__field(unsigned int, duration)
),
TP_fast_assign(
WIPHY_ASSIGN;
WDEV_ASSIGN;
CHAN_ASSIGN(chan);
- __entry->channel_type = channel_type;
__entry->duration = duration;
),
- TP_printk(WIPHY_PR_FMT WDEV_PR_FMT CHAN_PR_FMT ", channel type: %d, duration: %u",
- WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, __entry->channel_type,
- __entry->duration)
+ TP_printk(WIPHY_PR_FMT WDEV_PR_FMT CHAN_PR_FMT ", duration: %u",
+ WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, __entry->duration)
);

TRACE_EVENT(rdev_return_int_cookie,
@@ -1631,18 +1628,13 @@ TRACE_EVENT(rdev_cancel_remain_on_channel,
TRACE_EVENT(rdev_mgmt_tx,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
- enum nl80211_channel_type channel_type,
- bool channel_type_valid, unsigned int wait, bool no_cck,
- bool dont_wait_for_ack),
- TP_ARGS(wiphy, wdev, chan, offchan, channel_type, channel_type_valid,
- wait, no_cck, dont_wait_for_ack),
+ unsigned int wait, bool no_cck, bool dont_wait_for_ack),
+ TP_ARGS(wiphy, wdev, chan, offchan, wait, no_cck, dont_wait_for_ack),
TP_STRUCT__entry(
WIPHY_ENTRY
WDEV_ENTRY
CHAN_ENTRY
__field(bool, offchan)
- __field(enum nl80211_channel_type, channel_type)
- __field(bool, channel_type_valid)
__field(unsigned int, wait)
__field(bool, no_cck)
__field(bool, dont_wait_for_ack)
@@ -1652,18 +1644,14 @@ TRACE_EVENT(rdev_mgmt_tx,
WDEV_ASSIGN;
CHAN_ASSIGN(chan);
__entry->offchan = offchan;
- __entry->channel_type = channel_type;
- __entry->channel_type_valid = channel_type_valid;
__entry->wait = wait;
__entry->no_cck = no_cck;
__entry->dont_wait_for_ack = dont_wait_for_ack;
),
- TP_printk(WIPHY_PR_FMT WDEV_PR_FMT CHAN_PR_FMT ", offchan: %s, "
- "channel type: %d, channel type valid: %s, wait: %u, "
- "no cck: %s, dont wait for ack: %s",
+ TP_printk(WIPHY_PR_FMT WDEV_PR_FMT CHAN_PR_FMT ", offchan: %s,"
+ " wait: %u, no cck: %s, dont wait for ack: %s",
WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG,
- BOOL_TO_STR(__entry->offchan), __entry->channel_type,
- BOOL_TO_STR(__entry->channel_type_valid), __entry->wait,
+ BOOL_TO_STR(__entry->offchan), __entry->wait,
BOOL_TO_STR(__entry->no_cck),
BOOL_TO_STR(__entry->dont_wait_for_ack))
);
@@ -1894,47 +1882,41 @@ TRACE_EVENT(cfg80211_michael_mic_failure,
TRACE_EVENT(cfg80211_ready_on_channel,
TP_PROTO(struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type, unsigned int duration),
- TP_ARGS(wdev, cookie, chan, channel_type, duration),
+ unsigned int duration),
+ TP_ARGS(wdev, cookie, chan, duration),
TP_STRUCT__entry(
WDEV_ENTRY
__field(u64, cookie)
CHAN_ENTRY
- __field(enum nl80211_channel_type, channel_type)
__field(unsigned int, duration)
),
TP_fast_assign(
WDEV_ASSIGN;
__entry->cookie = cookie;
CHAN_ASSIGN(chan);
- __entry->channel_type = channel_type;
__entry->duration = duration;
),
- TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", channel type: %d, duration: %u",
+ TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", duration: %u",
WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG,
- __entry->channel_type, __entry->duration)
+ __entry->duration)
);

TRACE_EVENT(cfg80211_ready_on_channel_expired,
TP_PROTO(struct wireless_dev *wdev, u64 cookie,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type),
- TP_ARGS(wdev, cookie, chan, channel_type),
+ struct ieee80211_channel *chan),
+ TP_ARGS(wdev, cookie, chan),
TP_STRUCT__entry(
WDEV_ENTRY
__field(u64, cookie)
CHAN_ENTRY
- __field(enum nl80211_channel_type, channel_type)
),
TP_fast_assign(
WDEV_ASSIGN;
__entry->cookie = cookie;
CHAN_ASSIGN(chan);
- __entry->channel_type = channel_type;
),
- TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", channel type: %d",
- WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG,
- __entry->channel_type)
+ TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT,
+ WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG)
);

TRACE_EVENT(cfg80211_new_sta,
--
1.8.0


2012-11-09 20:17:02

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

From: Johannes Berg <[email protected]>

Change nl80211 to support specifying a VHT (or HT)
using the control channel frequency (as before) and
new attributes for the channel width and first and
second center frequency. The old channel type is of
course still supported for HT.

Also change the cfg80211 channel definition struct
to support these by adding the relevant fields to
it (and removing the _type field.)

This also adds new helper functions:
- cfg80211_chandef_create to create a channel def
struct given the control channel and channel type,
- cfg80211_chandef_identical to check if two channel
definitions are identical
- cfg80211_chandef_compatible to check if the given
channel definitions are compatible, and return the
wider of the two

Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 10 +-
include/net/cfg80211.h | 73 ++++++++++-
include/uapi/linux/nl80211.h | 61 +++++++--
net/mac80211/cfg.c | 5 +-
net/mac80211/ibss.c | 13 +-
net/wireless/chan.c | 193 ++++++++++++++++++++++++++---
net/wireless/core.h | 2 +
net/wireless/ibss.c | 4 +-
net/wireless/mesh.c | 4 +-
net/wireless/nl80211.c | 165 +++++++++++++++++-------
net/wireless/trace.h | 28 +++--
net/wireless/wext-compat.c | 4 +-
net/wireless/wext-sme.c | 3 +-
13 files changed, 457 insertions(+), 108 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index c0cc2e5..51bbe85 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1099,12 +1099,10 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
"channel switch notify nw_type %d freq %d mode %d\n",
vif->nw_type, freq, mode);

- chandef.chan = ieee80211_get_channel(vif->ar->wiphy, freq);
- if (WARN_ON(!chandef.chan))
- return;
-
- chandef._type = (mode == WMI_11G_HT20) ?
- NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT;
+ cfg80211_chandef_create(&chandef,
+ ieee80211_get_channel(vif->ar->wiphy, freq),
+ (mode == WMI_11G_HT20) ?
+ NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);

cfg80211_ch_switch_notify(vif->ndev, &chandef);
}
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ddcc6ca..0712421 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -308,21 +308,86 @@ struct key_params {
/**
* struct cfg80211_chan_def - channel definition
* @chan: the (control) channel
- * @_type: the channel type, don't use this field,
- * use cfg80211_get_chandef_type() if needed.
+ * @width: channel width
+ * @center_freq1: center frequency of first segment
+ * @center_freq2: center frequency of second segment
+ * (only with 80+80 MHz)
*/
struct cfg80211_chan_def {
struct ieee80211_channel *chan;
- enum nl80211_channel_type _type;
+ enum nl80211_chan_width width;
+ u32 center_freq1;
+ u32 center_freq2;
};

+/**
+ * cfg80211_get_chandef_type - return old channel type from chandef
+ * @chandef: the channel definition
+ *
+ * Returns the old channel type (NOHT, HT20, HT40+/-) from a given
+ * chandef, which must have a bandwidth allowing this conversion.
+ */
static inline enum nl80211_channel_type
cfg80211_get_chandef_type(const struct cfg80211_chan_def *chandef)
{
- return chandef->_type;
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ return NL80211_CHAN_NO_HT;
+ case NL80211_CHAN_WIDTH_20:
+ return NL80211_CHAN_HT20;
+ case NL80211_CHAN_WIDTH_40:
+ if (chandef->center_freq1 > chandef->chan->center_freq)
+ return NL80211_CHAN_HT40PLUS;
+ return NL80211_CHAN_HT40MINUS;
+ default:
+ WARN_ON(1);
+ return NL80211_CHAN_NO_HT;
+ }
+}
+
+/**
+ * cfg80211_chandef_create - create channel definition using channel type
+ * @chandef: the channel definition struct to fill
+ * @channel: the control channel
+ * @chantype: the channel type
+ *
+ * Given a channel type, create a channel definition.
+ */
+void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type chantype);
+
+/**
+ * cfg80211_chandef_identical - check if two channel definitions are identical
+ * @chandef1: first channel definition
+ * @chandef2: second channel definition
+ *
+ * Returns %true if the channels defined by the channel definitions are
+ * identical, %false otherwise.
+ */
+static inline bool
+cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
+ const struct cfg80211_chan_def *chandef2)
+{
+ return (chandef1->chan == chandef2->chan &&
+ chandef1->width == chandef2->width &&
+ chandef1->center_freq1 == chandef2->center_freq1 &&
+ chandef1->center_freq2 == chandef2->center_freq2);
}

/**
+ * cfg80211_chandef_compatible - check if two channel definitions are compatible
+ * @chandef1: first channel definition
+ * @chandef2: second channel definition
+ *
+ * Returns %NULL if the given channel definitions are incompatible,
+ * chandef1 or chandef2 otherwise.
+ */
+const struct cfg80211_chan_def *
+cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1,
+ const struct cfg80211_chan_def *chandef2);
+
+/**
* enum survey_info_flags - survey information flags
*
* @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index ac5c446..ea33515 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -118,8 +118,9 @@
* to get a list of all present wiphys.
* @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
* %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
- * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
- * %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT,
+ * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ (and the
+ * attributes determining the channel width; this is used for setting
+ * monitor mode channel), %NL80211_ATTR_WIPHY_RETRY_SHORT,
* %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
* and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
* However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
@@ -171,7 +172,7 @@
* %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
* %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT.
* The channel to use can be set on the interface or be given using the
- * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_CHANNEL_TYPE attrs.
+ * %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width.
* @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
* @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
* @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
@@ -471,8 +472,8 @@
* command is used as an event to indicate the that a trigger level was
* reached.
* @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ
- * and %NL80211_ATTR_WIPHY_CHANNEL_TYPE) the given interface (identifed
- * by %NL80211_ATTR_IFINDEX) shall operate on.
+ * and the attributes determining channel width) the given interface
+ * (identifed by %NL80211_ATTR_IFINDEX) shall operate on.
* In case multiple channels are supported by the device, the mechanism
* with which it switches channels is implementation-defined.
* When a monitor interface is given, it can only switch channel while
@@ -560,8 +561,8 @@
*
* @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels
* independently of the userspace SME, send this event indicating
- * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with
- * %NL80211_ATTR_WIPHY_CHANNEL_TYPE.
+ * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the
+ * attributes determining channel width.
*
* @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by
* its %NL80211_ATTR_WDEV identifier. It must have been created with
@@ -765,14 +766,26 @@ enum nl80211_commands {
* /sys/class/ieee80211/<phyname>/index
* @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
* @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
- * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
+ * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz,
+ * defines the channel together with the (deprecated)
+ * %NL80211_ATTR_WIPHY_CHANNEL_TYPE attribute or the attributes
+ * %NL80211_ATTR_CHANNEL_WIDTH and if needed %NL80211_ATTR_CENTER_FREQ1
+ * and %NL80211_ATTR_CENTER_FREQ2
+ * @NL80211_ATTR_CHANNEL_WIDTH: u32 attribute containing one of the values
+ * of &enum nl80211_chan_width, describing the channel width. See the
+ * documentation of the enum for more information.
+ * @NL80211_ATTR_CENTER_FREQ1: Center frequency of the first part of the
+ * channel, used for anything but 20 MHz bandwidth
+ * @NL80211_ATTR_CENTER_FREQ2: Center frequency of the second part of the
+ * channel, used only for 80+80 MHz bandwidth
* @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
- * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
+ * if HT20 or HT40 are to be used (i.e., HT disabled if not included):
* NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
* this attribute)
* NL80211_CHAN_HT20 = HT20 only
* NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
* NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
+ * This attribute is now deprecated.
* @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is
* less than or equal to the RTS threshold; allowed range: 1..255;
* dot11ShortRetryLimit; u8
@@ -1547,6 +1560,10 @@ enum nl80211_attrs {

NL80211_ATTR_SCAN_FLAGS,

+ NL80211_ATTR_CHANNEL_WIDTH,
+ NL80211_ATTR_CENTER_FREQ1,
+ NL80211_ATTR_CENTER_FREQ2,
+
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
@@ -2453,6 +2470,32 @@ enum nl80211_channel_type {
};

/**
+ * enum nl80211_chan_width - channel width definitions
+ *
+ * These values are used with the %NL80211_ATTR_CHANNEL_WIDTH
+ * attribute.
+ *
+ * @NL80211_CHAN_WIDTH_20_NOHT: 20 MHz, non-HT channel
+ * @NL80211_CHAN_WIDTH_20: 20 MHz HT channel
+ * @NL80211_CHAN_WIDTH_40: 40 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ * attribute must be provided as well
+ * @NL80211_CHAN_WIDTH_80: 80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ * attribute must be provided as well
+ * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ * attribute must be provided as well
+ * @NL80211_CHAN_WIDTH_80P80: 80+80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ * and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well
+ */
+enum nl80211_chan_width {
+ NL80211_CHAN_WIDTH_20_NOHT,
+ NL80211_CHAN_WIDTH_20,
+ NL80211_CHAN_WIDTH_40,
+ NL80211_CHAN_WIDTH_80,
+ NL80211_CHAN_WIDTH_160,
+ NL80211_CHAN_WIDTH_80P80,
+};
+
+/**
* enum nl80211_bss - netlink attributes for a BSS
*
* @__NL80211_BSS_INVALID: invalid
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 4327443..d83bb68 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3152,8 +3152,9 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (chanctx_conf) {
- chandef->chan = chanctx_conf->channel;
- chandef->_type = chanctx_conf->channel_type;
+ cfg80211_chandef_create(chandef,
+ chanctx_conf->channel,
+ chanctx_conf->channel_type);
ret = 0;
}
rcu_read_unlock();
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index b7bfb4f..c427cf3 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -52,6 +52,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
u32 bss_change;
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
struct cfg80211_chan_def chandef;
+ enum nl80211_channel_type chan_type;

lockdep_assert_held(&ifibss->mtx);

@@ -79,13 +80,13 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,

sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;

- chandef.chan = chan;
- chandef._type = ifibss->channel_type;
+ chan_type = ifibss->channel_type;
+ cfg80211_chandef_create(&chandef, chan, chan_type);
if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef))
- chandef._type = NL80211_CHAN_HT20;
+ chan_type = NL80211_CHAN_HT20;

ieee80211_vif_release_channel(sdata);
- if (ieee80211_vif_use_channel(sdata, chan, chandef._type,
+ if (ieee80211_vif_use_channel(sdata, chan, chan_type,
ifibss->fixed_channel ?
IEEE80211_CHANCTX_SHARED :
IEEE80211_CHANCTX_EXCLUSIVE)) {
@@ -159,7 +160,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
ifibss->ie, ifibss->ie_len);

/* add HT capability and information IEs */
- if (chandef._type != NL80211_CHAN_NO_HT &&
+ if (chan_type != NL80211_CHAN_NO_HT &&
sband->ht_cap.ht_supported) {
pos = skb_put(skb, 4 +
sizeof(struct ieee80211_ht_cap) +
@@ -172,7 +173,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
* keep them at 0
*/
pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
- chan, chandef._type, 0);
+ chan, chan_type, 0);
}

if (local->hw.queues >= IEEE80211_NUM_ACS) {
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index e834422..3d46c38 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -11,43 +11,196 @@
#include "core.h"
#include "rdev-ops.h"

-bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
- struct cfg80211_chan_def *chandef)
+void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type chan_type)
{
- struct ieee80211_channel *sec_chan;
- int diff;
+ if (WARN_ON(!chan))
+ return;

- trace_cfg80211_reg_can_beacon(wiphy, chandef);
+ chandef->chan = chan;
+ chandef->center_freq2 = 0;

- switch (chandef->_type) {
+ switch (chan_type) {
+ case NL80211_CHAN_NO_HT:
+ chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
+ chandef->center_freq1 = chan->center_freq;
+ break;
+ case NL80211_CHAN_HT20:
+ chandef->width = NL80211_CHAN_WIDTH_20;
+ chandef->center_freq1 = chan->center_freq;
+ break;
case NL80211_CHAN_HT40PLUS:
- diff = 20;
+ chandef->width = NL80211_CHAN_WIDTH_40;
+ chandef->center_freq1 = chan->center_freq + 10;
break;
case NL80211_CHAN_HT40MINUS:
- diff = -20;
+ chandef->width = NL80211_CHAN_WIDTH_40;
+ chandef->center_freq1 = chan->center_freq - 10;
+ break;
+ default:
+ WARN_ON(1);
+ }
+}
+EXPORT_SYMBOL(cfg80211_chandef_create);
+
+bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef)
+{
+ u32 control_freq;
+
+ if (!chandef->chan)
+ return false;
+
+ control_freq = chandef->chan->center_freq;
+
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20:
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ if (chandef->center_freq1 != control_freq)
+ return false;
+ if (chandef->center_freq2)
+ return false;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ if (chandef->center_freq1 != control_freq + 10 &&
+ chandef->center_freq1 != control_freq - 10)
+ return false;
+ if (chandef->center_freq2)
+ return false;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ if (chandef->center_freq1 != control_freq + 30 &&
+ chandef->center_freq1 != control_freq + 10 &&
+ chandef->center_freq1 != control_freq - 10 &&
+ chandef->center_freq1 != control_freq - 30)
+ return false;
+ if (!chandef->center_freq2)
+ return false;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ if (chandef->center_freq1 != control_freq + 30 &&
+ chandef->center_freq1 != control_freq + 10 &&
+ chandef->center_freq1 != control_freq - 10 &&
+ chandef->center_freq1 != control_freq - 30)
+ return false;
+ if (chandef->center_freq2)
+ return false;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ if (chandef->center_freq1 != control_freq + 70 &&
+ chandef->center_freq1 != control_freq + 50 &&
+ chandef->center_freq1 != control_freq + 30 &&
+ chandef->center_freq1 != control_freq + 10 &&
+ chandef->center_freq1 != control_freq - 10 &&
+ chandef->center_freq1 != control_freq - 30 &&
+ chandef->center_freq1 != control_freq - 50 &&
+ chandef->center_freq1 != control_freq - 70)
+ return false;
+ if (chandef->center_freq2)
+ return false;
break;
default:
- trace_cfg80211_return_bool(true);
- return true;
+ return false;
+ }
+
+ return true;
+}
+
+const struct cfg80211_chan_def *
+cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
+ const struct cfg80211_chan_def *c2)
+{
+ /* If they are identical, return */
+ if (cfg80211_chandef_identical(c1, c2))
+ return c1;
+
+ /* otherwise, must have same control channel */
+ if (c1->chan != c2->chan)
+ return NULL;
+
+ /*
+ * If they have the same width, but aren't identical,
+ * then they can't be compatible.
+ */
+ if (c1->width == c2->width)
+ return NULL;
+
+ if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
+ c1->width == NL80211_CHAN_WIDTH_20)
+ return c2;
+
+ if (c2->width == NL80211_CHAN_WIDTH_20_NOHT ||
+ c2->width == NL80211_CHAN_WIDTH_20)
+ return c1;
+
+ /* TODO: not sure how to handle 80/160/80+80 */
+
+ return NULL;
+}
+EXPORT_SYMBOL(cfg80211_chandef_compatible);
+
+static bool cfg80211_check_beacon_chans(struct wiphy *wiphy,
+ u32 center_freq, u32 bw)
+{
+ struct ieee80211_channel *c;
+ u32 freq;
+
+ for (freq = center_freq - bw/2 + 10;
+ freq <= center_freq + bw/2 - 10;
+ freq += 20) {
+ c = ieee80211_get_channel(wiphy, freq);
+ if (!c || c->flags & (IEEE80211_CHAN_DISABLED |
+ IEEE80211_CHAN_PASSIVE_SCAN |
+ IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_RADAR))
+ return false;
}

- sec_chan = ieee80211_get_channel(wiphy,
- chandef->chan->center_freq + diff);
- if (!sec_chan) {
+ return true;
+}
+
+bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef)
+{
+ u32 width;
+ bool res;
+
+ trace_cfg80211_reg_can_beacon(wiphy, chandef);
+
+ if (WARN_ON(!cfg80211_chan_def_valid(chandef))) {
trace_cfg80211_return_bool(false);
return false;
}

- /* we'll need a DFS capability later */
- if (sec_chan->flags & (IEEE80211_CHAN_DISABLED |
- IEEE80211_CHAN_PASSIVE_SCAN |
- IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_RADAR)) {
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ width = 20;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ width = 40;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ case NL80211_CHAN_WIDTH_80P80:
+ width = 80;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ width = 160;
+ break;
+ default:
+ WARN_ON_ONCE(1);
trace_cfg80211_return_bool(false);
return false;
}
- trace_cfg80211_return_bool(true);
- return true;
+
+ res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq1, width);
+
+ if (res && chandef->center_freq2)
+ res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq2,
+ width);
+
+ trace_cfg80211_return_bool(res);
+ return res;
}
EXPORT_SYMBOL(cfg80211_reg_can_beacon);

diff --git a/net/wireless/core.h b/net/wireless/core.h
index 6183a0d..99f4e6a 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -483,6 +483,8 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, int num);

+bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef);
+
#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10

#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index ccc8865..9b9551e 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -252,7 +252,7 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,

/* try to find an IBSS channel if none requested ... */
if (!wdev->wext.ibss.chandef.chan) {
- wdev->wext.ibss.chandef._type = NL80211_CHAN_NO_HT;
+ wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT;

for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
struct ieee80211_supported_band *sband;
@@ -352,7 +352,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,

if (chan) {
wdev->wext.ibss.chandef.chan = chan;
- wdev->wext.ibss.chandef._type = NL80211_CHAN_NO_HT;
+ wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
wdev->wext.ibss.channel_fixed = true;
} else {
/* cfg80211_ibss_wext_join will pick one if needed */
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 12b5a57..3ee5a72 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -146,7 +146,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
if (!setup->chandef.chan)
return -EINVAL;

- setup->chandef._type = NL80211_CHAN_NO_HT;
+ setup->chandef.width = NL80211_CHAN_WIDTH_20_NOHT;;
}

if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
@@ -198,7 +198,7 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
* compatible with 802.11 mesh.
*/
if (rdev->ops->libertas_set_mesh_channel) {
- if (chandef->_type != NL80211_CHAN_NO_HT)
+ if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT)
return -EINVAL;

if (!netif_running(wdev->netdev))
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index bed5a0e..6c9c6bc 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -223,8 +223,13 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
.len = 20-1 },
[NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
+
[NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
[NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
+ [NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
+ [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
+ [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },
+
[NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 },
[NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 },
[NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
@@ -1360,25 +1365,21 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
wdev->iftype == NL80211_IFTYPE_P2P_GO;
}

-static bool nl80211_valid_channel_type(struct genl_info *info,
- enum nl80211_channel_type *channel_type)
+static int nl80211_check_sec_chans(struct cfg80211_registered_device *rdev,
+ u32 center_freq, u32 bw)
{
- enum nl80211_channel_type tmp;
-
- if (!info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
- return false;
+ struct ieee80211_channel *c;
+ u32 freq;

- tmp = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
- if (tmp != NL80211_CHAN_NO_HT &&
- tmp != NL80211_CHAN_HT20 &&
- tmp != NL80211_CHAN_HT40PLUS &&
- tmp != NL80211_CHAN_HT40MINUS)
- return false;
-
- if (channel_type)
- *channel_type = tmp;
+ for (freq = center_freq - bw/2 + 10;
+ freq <= center_freq + bw/2 - 10;
+ freq += 20) {
+ c = ieee80211_get_channel(&rdev->wiphy, freq);
+ if (!c || c->flags & IEEE80211_CHAN_DISABLED)
+ return -EINVAL;
+ }

- return true;
+ return 0;
}

static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
@@ -1386,9 +1387,8 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
struct cfg80211_chan_def *chandef)
{
struct ieee80211_sta_ht_cap *ht_cap;
- struct ieee80211_channel *sc;
- u32 control_freq;
- int offs;
+ struct ieee80211_sta_vht_cap *vht_cap;
+ u32 control_freq, width;

if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
return -EINVAL;
@@ -1396,47 +1396,103 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);

chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq);
- chandef->_type = NL80211_CHAN_NO_HT;
-
- if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
- !nl80211_valid_channel_type(info, &chandef->_type))
- return -EINVAL;
+ chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
+ chandef->center_freq1 = control_freq;
+ chandef->center_freq2 = 0;

/* Primary channel not allowed */
if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED)
return -EINVAL;

+ if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+ enum nl80211_channel_type chantype;
+
+ chantype = nla_get_u32(
+ info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+
+ switch (chantype) {
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
+ case NL80211_CHAN_HT40PLUS:
+ case NL80211_CHAN_HT40MINUS:
+ cfg80211_chandef_create(chandef, chandef->chan,
+ chantype);
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else if (info->attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
+ if (!info->attrs[NL80211_ATTR_CENTER_FREQ1])
+ return -EINVAL;
+ chandef->width =
+ nla_get_u32(info->attrs[NL80211_ATTR_CHANNEL_WIDTH]);
+ chandef->center_freq1 =
+ nla_get_u32(info->attrs[NL80211_ATTR_CENTER_FREQ1]);
+ if (info->attrs[NL80211_ATTR_CENTER_FREQ2])
+ chandef->center_freq2 =
+ nla_get_u32(
+ info->attrs[NL80211_ATTR_CENTER_FREQ2]);
+ }
+
ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap;
+ vht_cap = &rdev->wiphy.bands[chandef->chan->band]->vht_cap;

- switch (chandef->_type) {
- case NL80211_CHAN_NO_HT:
+ if (!cfg80211_chan_def_valid(chandef))
+ return -EINVAL;
+
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20:
+ if (!ht_cap->ht_supported)
+ return -EINVAL;
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ width = 20;
break;
- case NL80211_CHAN_HT40MINUS:
- if (chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
+ case NL80211_CHAN_WIDTH_40:
+ width = 40;
+ /* quick early regulatory check */
+ if (chandef->center_freq1 < control_freq &&
+ chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
+ return -EINVAL;
+ if (chandef->center_freq1 > control_freq &&
+ chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
+ return -EINVAL;
+ if (!ht_cap->ht_supported)
return -EINVAL;
- offs = -20;
- /* fall through */
- case NL80211_CHAN_HT40PLUS:
- if (chandef->_type == NL80211_CHAN_HT40PLUS) {
- if (chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
- return -EINVAL;
- offs = 20;
- }
if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
return -EINVAL;
-
- sc = ieee80211_get_channel(&rdev->wiphy,
- chandef->chan->center_freq + offs);
- if (!sc || sc->flags & IEEE80211_CHAN_DISABLED)
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ width = 80;
+ if (!vht_cap->vht_supported)
return -EINVAL;
- /* fall through */
- case NL80211_CHAN_HT20:
- if (!ht_cap->ht_supported)
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ width = 80;
+ if (!vht_cap->vht_supported)
+ return -EINVAL;
+ if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))
+ return -EINVAL;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ width = 160;
+ if (!vht_cap->vht_supported)
+ return -EINVAL;
+ if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ))
return -EINVAL;
break;
+ default:
+ return -EINVAL;
}

+ if (nl80211_check_sec_chans(rdev, chandef->center_freq1, width))
+ return -EINVAL;
+ if (chandef->center_freq2 &&
+ nl80211_check_sec_chans(rdev, chandef->center_freq2, width))
+ return -EINVAL;
+
+ /* XXX: missing regulatory check on bandwidth */
+
return 0;
}

@@ -1800,10 +1856,28 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
static int nl80211_send_chandef(struct sk_buff *msg,
struct cfg80211_chan_def *chandef)
{
+ WARN_ON(!cfg80211_chan_def_valid(chandef));
+
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
chandef->chan->center_freq))
return -ENOBUFS;
- if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, chandef->_type))
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ case NL80211_CHAN_WIDTH_40:
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ cfg80211_get_chandef_type(chandef)))
+ return -ENOBUFS;
+ break;
+ default:
+ break;
+ }
+ if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width))
+ return -ENOBUFS;
+ if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1))
+ return -ENOBUFS;
+ if (chandef->center_freq2 &&
+ nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2))
return -ENOBUFS;
return 0;
}
@@ -5471,7 +5545,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
if (IS_ERR(connkeys))
return PTR_ERR(connkeys);

- if ((ibss.chandef._type != NL80211_CHAN_NO_HT) && no_ht) {
+ if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
+ no_ht) {
kfree(connkeys);
return -EINVAL;
}
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index d3906db..fbb9217 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -126,25 +126,33 @@
#define CHAN_PR_FMT ", band: %d, freq: %u"
#define CHAN_PR_ARG __entry->band, __entry->center_freq

-#define CHAN_DEF_ENTRY __field(enum ieee80211_band, band) \
- __field(u16, center_freq) \
- __field(u32, channel_type)
+#define CHAN_DEF_ENTRY __field(enum ieee80211_band, band) \
+ __field(u32, control_freq) \
+ __field(u32, width) \
+ __field(u32, center_freq1) \
+ __field(u32, center_freq2)
#define CHAN_DEF_ASSIGN(chandef) \
do { \
if ((chandef)->chan) { \
__entry->band = (chandef)->chan->band; \
- __entry->center_freq = \
+ __entry->control_freq = \
(chandef)->chan->center_freq; \
- __entry->channel_type = (chandef)->_type; \
+ __entry->width = (chandef)->width; \
+ __entry->center_freq1 = (chandef)->center_freq1;\
+ __entry->center_freq2 = (chandef)->center_freq2;\
} else { \
__entry->band = 0; \
- __entry->center_freq = 0; \
- __entry->channel_type = 0; \
+ __entry->control_freq = 0; \
+ __entry->width = 0; \
+ __entry->center_freq1 = 0; \
+ __entry->center_freq2 = 0; \
} \
} while (0)
-#define CHAN_DEF_PR_FMT ", band: %d, freq: %u, chantype: %d"
-#define CHAN_DEF_PR_ARG __entry->band, __entry->center_freq, \
- __entry->channel_type
+#define CHAN_DEF_PR_FMT \
+ ", band: %d, control freq: %u, width: %d, cf1: %u, cf2: %u"
+#define CHAN_DEF_PR_ARG __entry->band, __entry->control_freq, \
+ __entry->width, __entry->center_freq1, \
+ __entry->center_freq2

#define SINFO_ENTRY __field(int, generation) \
__field(u32, connected_time) \
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index da3307f..f9680c9 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -785,7 +785,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_chan_def chandef = {
- ._type = NL80211_CHAN_NO_HT,
+ .width = NL80211_CHAN_WIDTH_20_NOHT,
};
int freq, err;

@@ -800,6 +800,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
return freq;
if (freq == 0)
return -EINVAL;
+ chandef.center_freq1 = freq;
chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
if (!chandef.chan)
return -EINVAL;
@@ -813,6 +814,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
return freq;
if (freq == 0)
return -EINVAL;
+ chandef.center_freq1 = freq;
chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
if (!chandef.chan)
return -EINVAL;
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index e6e5dbf..873af63 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -120,7 +120,8 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
*/
if (chan && !wdev->wext.connect.ssid_len) {
struct cfg80211_chan_def chandef = {
- ._type = NL80211_CHAN_NO_HT,
+ .width = NL80211_CHAN_WIDTH_20_NOHT,
+ .center_freq1 = freq,
};

chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
--
1.8.0


2012-11-20 09:39:27

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

On Tue, 2012-11-20 at 09:41 +0100, Johannes Berg wrote:
> On Tue, 2012-11-20 at 13:57 +0530, Mahesh Palivela wrote:
>
> > > + for (freq = center_freq - bw/2 + 10;
> > > + freq <= center_freq + bw/2 - 10;
> > > + freq += 20) {
> > > + c = ieee80211_get_channel(wiphy, freq);
> > > + if (!c || c->flags & (IEEE80211_CHAN_DISABLED |
> > > + IEEE80211_CHAN_PASSIVE_SCAN |
> > > + IEEE80211_CHAN_NO_IBSS |
> > > + IEEE80211_CHAN_RADAR))
> > > + return false;
>
>
> > > + for (freq = center_freq - bw/2 + 10;
> > > + freq <= center_freq + bw/2 - 10;
> > > + freq += 20) {
> > > + c = ieee80211_get_channel(&rdev->wiphy, freq);
> > > + if (!c || c->flags & IEEE80211_CHAN_DISABLED)
> > > + return -EINVAL;
>
>
> > For loops in both functions seems to be similar. One return false, other
> > return -EINVAL. Can we remove duplication?
>
> True, but they check different flags. I suppose we could have a common
> function where the checked flags are passed in, I can try that.

I'll add this to the patch:

http://p.sipsolutions.net/24eb25fb98ef2d0b.txt


2012-11-16 13:27:56

by Johannes Berg

[permalink] [raw]
Subject: Re: VHT support, take 2

On Thu, 2012-11-15 at 17:39 +0530, Mahesh Palivela wrote:

> vht regulatory code already posted long back. After went through several
> back n forth emails from Luis Rodriguez, accepted the patch.
> But not commited anywhere.
> Now I have to change that to match to new structs like chan_def etc from
> the vht channel work patches you posted 5 days back.
>
> Also helper funcs to replace chan->flags bit checking to dynamically
> check channel through regulatory

Yeah, actually I'm not sure it's that easy. We'll also need per
bandwidth TX power restrictions, raise the 40 MHz bandwidth restriction
to 160 MHz (or get rid of it entirely), etc. That seems to require a new
regulatory database format?

johannes


2012-11-15 11:01:00

by Mahesh Palivela

[permalink] [raw]
Subject: Re: [RFC v2 2/8] nl80211: add documentation for channel type

On 11/10/2012 01:47 AM, Johannes Berg wrote:
> From: Johannes Berg <[email protected]>
>
> Signed-off-by: Johannes Berg <[email protected]>
> ---
> include/uapi/linux/nl80211.h | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
> index d33d780..ac5c446 100644
> --- a/include/uapi/linux/nl80211.h
> +++ b/include/uapi/linux/nl80211.h
> @@ -2436,6 +2436,15 @@ enum nl80211_ac {
> #define NL80211_TXQ_Q_BE NL80211_AC_BE
> #define NL80211_TXQ_Q_BK NL80211_AC_BK
>
> +/**
> + * enum nl80211_channel_type - channel type
> + * @NL80211_CHAN_NO_HT: 20 MHz, non-HT channel
> + * @NL80211_CHAN_HT20: 20 MHz HT channel
> + * @NL80211_CHAN_HT40MINUS: HT40 channel, secondary channel
> + * below the control channel
> + * @NL80211_CHAN_HT40PLUS: HT40 channel, secondary channel
> + * below the control channel

Typo. above the control channel

> + */
> enum nl80211_channel_type {
> NL80211_CHAN_NO_HT,
> NL80211_CHAN_HT20,
>

2012-11-20 06:03:48

by Mahesh Palivela

[permalink] [raw]
Subject: Re: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

On 11/19/2012 07:41 PM, Johannes Berg wrote:
> On Mon, 2012-11-19 at 17:48 +0530, Mahesh Palivela wrote:
>
>>> + case NL80211_CHAN_WIDTH_160:
>>> + if (chandef->center_freq1 != control_freq + 70 &&
>>> + chandef->center_freq1 != control_freq + 50 &&
>>> + chandef->center_freq1 != control_freq + 30 &&
>>> + chandef->center_freq1 != control_freq + 10 &&
>>> + chandef->center_freq1 != control_freq - 10 &&
>>> + chandef->center_freq1 != control_freq - 30 &&
>>> + chandef->center_freq1 != control_freq - 50 &&
>>> + chandef->center_freq1 != control_freq - 70)
>>> + return false;
>>
>> Should we create a macro instead of +70 to -70 to take care of all 3
>> cases 80, 80p80 and 160?
>
> Not sure, I hope we won't duplicate this code anywhere else, so I don't
> really think we need to?
>

you kind of used it in cfg80211_check_beacon_chans() in wireless/chan.c

for (freq = center_freq - bw/2 + 10;
freq <= center_freq + bw/2 - 10;
freq += 20)

we can use in 3 switch cases, 80, 80p80 and 160.

2012-11-19 14:11:14

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

On Mon, 2012-11-19 at 17:48 +0530, Mahesh Palivela wrote:

> > + case NL80211_CHAN_WIDTH_160:
> > + if (chandef->center_freq1 != control_freq + 70 &&
> > + chandef->center_freq1 != control_freq + 50 &&
> > + chandef->center_freq1 != control_freq + 30 &&
> > + chandef->center_freq1 != control_freq + 10 &&
> > + chandef->center_freq1 != control_freq - 10 &&
> > + chandef->center_freq1 != control_freq - 30 &&
> > + chandef->center_freq1 != control_freq - 50 &&
> > + chandef->center_freq1 != control_freq - 70)
> > + return false;
>
> Should we create a macro instead of +70 to -70 to take care of all 3
> cases 80, 80p80 and 160?

Not sure, I hope we won't duplicate this code anywhere else, so I don't
really think we need to?

johannes


2012-11-09 20:17:04

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2 6/8] nl80211/cfg80211: add VHT MCS support

From: Johannes Berg <[email protected]>

Add support for reporting and calculating VHT MCSes.

Note that I'm not completely sure that the bitrate
calculations are correct, nor that they can't be
simplified.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/cfg80211.h | 24 +++++++++-----
include/uapi/linux/nl80211.h | 12 ++++++-
net/wireless/nl80211.c | 58 +++++++++++++++++++++++++---------
net/wireless/util.c | 74 +++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 144 insertions(+), 24 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 0712421..fe0c8f5 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -662,16 +662,24 @@ enum station_info_flags {
* Used by the driver to indicate the specific rate transmission
* type for 802.11n transmissions.
*
- * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled
- * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission
+ * @RATE_INFO_FLAGS_MCS: mcs field filled with HT MCS
+ * @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS
+ * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 MHz width transmission
+ * @RATE_INFO_FLAGS_80_MHZ_WIDTH: 80 MHz width transmission
+ * @RATE_INFO_FLAGS_80P80_MHZ_WIDTH: 80+80 MHz width transmission
+ * @RATE_INFO_FLAGS_160_MHZ_WIDTH: 160 MHz width transmission
* @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
- * @RATE_INFO_FLAGS_60G: 60gHz MCS
+ * @RATE_INFO_FLAGS_60G: 60GHz MCS
*/
enum rate_info_flags {
- RATE_INFO_FLAGS_MCS = 1<<0,
- RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1,
- RATE_INFO_FLAGS_SHORT_GI = 1<<2,
- RATE_INFO_FLAGS_60G = 1<<3,
+ RATE_INFO_FLAGS_MCS = BIT(0),
+ RATE_INFO_FLAGS_VHT_MCS = BIT(1),
+ RATE_INFO_FLAGS_40_MHZ_WIDTH = BIT(2),
+ RATE_INFO_FLAGS_80_MHZ_WIDTH = BIT(3),
+ RATE_INFO_FLAGS_80P80_MHZ_WIDTH = BIT(4),
+ RATE_INFO_FLAGS_160_MHZ_WIDTH = BIT(5),
+ RATE_INFO_FLAGS_SHORT_GI = BIT(6),
+ RATE_INFO_FLAGS_60G = BIT(7),
};

/**
@@ -682,11 +690,13 @@ enum rate_info_flags {
* @flags: bitflag of flags from &enum rate_info_flags
* @mcs: mcs index if struct describes a 802.11n bitrate
* @legacy: bitrate in 100kbit/s for 802.11abg
+ * @nss: number of streams (VHT only)
*/
struct rate_info {
u8 flags;
u8 mcs;
u16 legacy;
+ u8 nss;
};

/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index ea33515..71b20cc 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1732,10 +1732,15 @@ struct nl80211_sta_flag_update {
* @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
* @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
* @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
- * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 MHz dualchannel bitrate
* @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
* @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s)
* @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @NL80211_RATE_INFO_VHT_MCS: MCS index for VHT (u8)
+ * @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8)
+ * @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate
+ * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate
+ * @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
*/
enum nl80211_rate_info {
@@ -1745,6 +1750,11 @@ enum nl80211_rate_info {
NL80211_RATE_INFO_40_MHZ_WIDTH,
NL80211_RATE_INFO_SHORT_GI,
NL80211_RATE_INFO_BITRATE32,
+ NL80211_RATE_INFO_VHT_MCS,
+ NL80211_RATE_INFO_VHT_NSS,
+ NL80211_RATE_INFO_80_MHZ_WIDTH,
+ NL80211_RATE_INFO_80P80_MHZ_WIDTH,
+ NL80211_RATE_INFO_160_MHZ_WIDTH,

/* keep last */
__NL80211_RATE_INFO_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 6c9c6bc..2d03380 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2905,29 +2905,52 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,

rate = nla_nest_start(msg, attr);
if (!rate)
- goto nla_put_failure;
+ return false;

/* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
bitrate = cfg80211_calculate_bitrate(info);
/* report 16-bit bitrate only if we can */
bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
- if ((bitrate > 0 &&
- nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) ||
- (bitrate_compat > 0 &&
- nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) ||
- ((info->flags & RATE_INFO_FLAGS_MCS) &&
- nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) ||
- ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) &&
- nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH)) ||
- ((info->flags & RATE_INFO_FLAGS_SHORT_GI) &&
- nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)))
- goto nla_put_failure;
+ if (bitrate > 0 &&
+ nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate))
+ return false;
+ if (bitrate_compat > 0 &&
+ nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
+ return false;
+
+ if (info->flags & RATE_INFO_FLAGS_MCS) {
+ if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
+ nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
+ nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
+ return false;
+ } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
+ if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
+ return false;
+ if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
+ nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH &&
+ nla_put_flag(msg, NL80211_RATE_INFO_80_MHZ_WIDTH))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_80P80_MHZ_WIDTH &&
+ nla_put_flag(msg, NL80211_RATE_INFO_80P80_MHZ_WIDTH))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_160_MHZ_WIDTH &&
+ nla_put_flag(msg, NL80211_RATE_INFO_160_MHZ_WIDTH))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
+ nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
+ return false;
+ }

nla_nest_end(msg, rate);
return true;
-
-nla_put_failure:
- return false;
}

static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
@@ -5514,6 +5537,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef))
return -EINVAL;

+ if (ibss.chandef.width > NL80211_CHAN_WIDTH_40)
+ return -EINVAL;
+ if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
+ !(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
+
ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];

diff --git a/net/wireless/util.c b/net/wireless/util.c
index 2964223..ae8f050 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -944,14 +944,86 @@ static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate)
return __mcs2bitrate[rate->mcs];
}

+static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
+{
+ static const u32 base[4][10] = {
+ { 6500000,
+ 13000000,
+ 19500000,
+ 26000000,
+ 39000000,
+ 52000000,
+ 58500000,
+ 65000000,
+ 78000000,
+ 0,
+ },
+ { 13500000,
+ 27000000,
+ 40500000,
+ 54000000,
+ 81000000,
+ 108000000,
+ 121500000,
+ 135000000,
+ 162000000,
+ 180000000,
+ },
+ { 29300000,
+ 58500000,
+ 87800000,
+ 117000000,
+ 175500000,
+ 234000000,
+ 263300000,
+ 292500000,
+ 351000000,
+ 390000000,
+ },
+ { 58500000,
+ 117000000,
+ 175500000,
+ 234000000,
+ 351000000,
+ 468000000,
+ 526500000,
+ 585000000,
+ 702000000,
+ 780000000,
+ },
+ };
+ u32 bitrate;
+ int idx;
+
+ if (WARN_ON_ONCE(rate->mcs > 9))
+ return 0;
+
+ idx = rate->flags & (RATE_INFO_FLAGS_160_MHZ_WIDTH |
+ RATE_INFO_FLAGS_80P80_MHZ_WIDTH) ? 3 :
+ rate->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH ? 2 :
+ rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH ? 1 : 0;
+
+ bitrate = base[idx][rate->mcs];
+ bitrate *= rate->nss;
+
+ if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
+ bitrate = (bitrate / 9) * 10;
+
+ /* do NOT round down here */
+ return (bitrate + 50000) / 100000;
+}
+
u32 cfg80211_calculate_bitrate(struct rate_info *rate)
{
int modulation, streams, bitrate;

- if (!(rate->flags & RATE_INFO_FLAGS_MCS))
+ if (!(rate->flags & RATE_INFO_FLAGS_MCS) &&
+ !(rate->flags & RATE_INFO_FLAGS_VHT_MCS))
return rate->legacy;
if (rate->flags & RATE_INFO_FLAGS_60G)
return cfg80211_calculate_bitrate_60g(rate);
+ if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
+ return cfg80211_calculate_bitrate_vht(rate);

/* the formula below does only work for MCS values smaller than 32 */
if (WARN_ON_ONCE(rate->mcs >= 32))
--
1.8.0


2012-11-19 12:18:14

by Mahesh Palivela

[permalink] [raw]
Subject: Re: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

On 11/10/2012 01:47 AM, Johannes Berg wrote:
> From: Johannes Berg <[email protected]>
> +bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef)
> +{
> + u32 control_freq;
> +
> + if (!chandef->chan)
> + return false;
> +
> + control_freq = chandef->chan->center_freq;
> +
> + switch (chandef->width) {
> + case NL80211_CHAN_WIDTH_20:
> + case NL80211_CHAN_WIDTH_20_NOHT:
> + if (chandef->center_freq1 != control_freq)
> + return false;
> + if (chandef->center_freq2)
> + return false;
> + break;
> + case NL80211_CHAN_WIDTH_40:
> + if (chandef->center_freq1 != control_freq + 10 &&
> + chandef->center_freq1 != control_freq - 10)
> + return false;
> + if (chandef->center_freq2)
> + return false;
> + break;
> + case NL80211_CHAN_WIDTH_80P80:
> + if (chandef->center_freq1 != control_freq + 30 &&
> + chandef->center_freq1 != control_freq + 10 &&
> + chandef->center_freq1 != control_freq - 10 &&
> + chandef->center_freq1 != control_freq - 30)
> + return false;
> + if (!chandef->center_freq2)
> + return false;
> + break;
> + case NL80211_CHAN_WIDTH_80:
> + if (chandef->center_freq1 != control_freq + 30 &&
> + chandef->center_freq1 != control_freq + 10 &&
> + chandef->center_freq1 != control_freq - 10 &&
> + chandef->center_freq1 != control_freq - 30)
> + return false;
> + if (chandef->center_freq2)
> + return false;
> + break;
> + case NL80211_CHAN_WIDTH_160:
> + if (chandef->center_freq1 != control_freq + 70 &&
> + chandef->center_freq1 != control_freq + 50 &&
> + chandef->center_freq1 != control_freq + 30 &&
> + chandef->center_freq1 != control_freq + 10 &&
> + chandef->center_freq1 != control_freq - 10 &&
> + chandef->center_freq1 != control_freq - 30 &&
> + chandef->center_freq1 != control_freq - 50 &&
> + chandef->center_freq1 != control_freq - 70)
> + return false;

Should we create a macro instead of +70 to -70 to take care of all 3
cases 80, 80p80 and 160?

> + if (chandef->center_freq2)



2012-11-20 07:27:15

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

On Tue, 2012-11-20 at 11:33 +0530, Mahesh Palivela wrote:
> On 11/19/2012 07:41 PM, Johannes Berg wrote:
> > On Mon, 2012-11-19 at 17:48 +0530, Mahesh Palivela wrote:
> >
> >>> + case NL80211_CHAN_WIDTH_160:
> >>> + if (chandef->center_freq1 != control_freq + 70 &&
> >>> + chandef->center_freq1 != control_freq + 50 &&
> >>> + chandef->center_freq1 != control_freq + 30 &&
> >>> + chandef->center_freq1 != control_freq + 10 &&
> >>> + chandef->center_freq1 != control_freq - 10 &&
> >>> + chandef->center_freq1 != control_freq - 30 &&
> >>> + chandef->center_freq1 != control_freq - 50 &&
> >>> + chandef->center_freq1 != control_freq - 70)
> >>> + return false;
> >>
> >> Should we create a macro instead of +70 to -70 to take care of all 3
> >> cases 80, 80p80 and 160?
> >
> > Not sure, I hope we won't duplicate this code anywhere else, so I don't
> > really think we need to?
> >
>
> you kind of used it in cfg80211_check_beacon_chans() in wireless/chan.c
>
> for (freq = center_freq - bw/2 + 10;
> freq <= center_freq + bw/2 - 10;
> freq += 20)
>
> we can use in 3 switch cases, 80, 80p80 and 160.

That's different code though, it iterates all the subchannels, while the
previous one checks the offset. I don't see how to unify that with a
single macro?

johannes


2012-11-20 11:59:59

by Mahesh Palivela

[permalink] [raw]
Subject: Re: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

On 11/20/2012 03:09 PM, Johannes Berg wrote:
> On Tue, 2012-11-20 at 09:41 +0100, Johannes Berg wrote:
>> On Tue, 2012-11-20 at 13:57 +0530, Mahesh Palivela wrote:
>>
>>>> + for (freq = center_freq - bw/2 + 10;
>>>> + freq <= center_freq + bw/2 - 10;
>>>> + freq += 20) {
>>>> + c = ieee80211_get_channel(wiphy, freq);
>>>> + if (!c || c->flags & (IEEE80211_CHAN_DISABLED |
>>>> + IEEE80211_CHAN_PASSIVE_SCAN |
>>>> + IEEE80211_CHAN_NO_IBSS |
>>>> + IEEE80211_CHAN_RADAR))
>>>> + return false;
>>
>>
>>>> + for (freq = center_freq - bw/2 + 10;
>>>> + freq <= center_freq + bw/2 - 10;
>>>> + freq += 20) {
>>>> + c = ieee80211_get_channel(&rdev->wiphy, freq);
>>>> + if (!c || c->flags & IEEE80211_CHAN_DISABLED)
>>>> + return -EINVAL;
>>
>>
>>> For loops in both functions seems to be similar. One return false, other
>>> return -EINVAL. Can we remove duplication?
>>
>> True, but they check different flags. I suppose we could have a common
>> function where the checked flags are passed in, I can try that.
>
> I'll add this to the patch:
>
> http://p.sipsolutions.net/24eb25fb98ef2d0b.txt
>

Looks good to me Johannes. Overall your VHT channel config
implementation done so well.
Partial regulatory check in nl80211_parse_chandef() has to be modified
to include BW check. I see your TODO comment there.

Thanks,
Mahesh

2012-11-18 11:05:00

by Johannes Berg

[permalink] [raw]
Subject: Re: VHT support, take 2

On Sun, 2012-11-18 at 12:03 +0100, Johannes Berg wrote:
> On Sat, 2012-11-17 at 15:34 -0800, Luis R. Rodriguez wrote:
>
> > > > The only thing mentioned which I had not considered is the per bandwidth
> > > > TX power restrictions. Where did these come from ?
> > >
> > > As usual, they come from the regulations :-)
> >
> > Which one in particular decided to add per bandwidth
> > TX power restrictions for VHT ?
>
> German regulations have always had bandwidth restrictions, we've just
> fuzzed around it by restricting it to the lowest common power between 20
> and 40 MHz bandwidth.

I should add: with VHT coming with 160 MHz channels, I don't think we
can continue to work around it that way as that would be really
limiting.

johannes


2012-11-09 20:17:00

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2 2/8] nl80211: add documentation for channel type

From: Johannes Berg <[email protected]>

Signed-off-by: Johannes Berg <[email protected]>
---
include/uapi/linux/nl80211.h | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index d33d780..ac5c446 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2436,6 +2436,15 @@ enum nl80211_ac {
#define NL80211_TXQ_Q_BE NL80211_AC_BE
#define NL80211_TXQ_Q_BK NL80211_AC_BK

+/**
+ * enum nl80211_channel_type - channel type
+ * @NL80211_CHAN_NO_HT: 20 MHz, non-HT channel
+ * @NL80211_CHAN_HT20: 20 MHz HT channel
+ * @NL80211_CHAN_HT40MINUS: HT40 channel, secondary channel
+ * below the control channel
+ * @NL80211_CHAN_HT40PLUS: HT40 channel, secondary channel
+ * below the control channel
+ */
enum nl80211_channel_type {
NL80211_CHAN_NO_HT,
NL80211_CHAN_HT20,
--
1.8.0


2012-11-15 12:09:11

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 2/8] nl80211: add documentation for channel type

On Thu, 2012-11-15 at 16:30 +0530, Mahesh Palivela wrote:

> > +/**
> > + * enum nl80211_channel_type - channel type
> > + * @NL80211_CHAN_NO_HT: 20 MHz, non-HT channel
> > + * @NL80211_CHAN_HT20: 20 MHz HT channel
> > + * @NL80211_CHAN_HT40MINUS: HT40 channel, secondary channel
> > + * below the control channel
> > + * @NL80211_CHAN_HT40PLUS: HT40 channel, secondary channel
> > + * below the control channel
>
> Typo. above the control channel

Good catch, thanks.

johannes


2012-11-09 20:17:02

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2 3/8] cfg80211: pass a channel definition struct

From: Johannes Berg <[email protected]>

Instead of passing a channel pointer and channel type
to all functions and driver methods, pass a new channel
definition struct. Right now, this struct contains just
the control channel and channel type, but for VHT this
will change.

Also, add a small inline cfg80211_get_chandef_type() so
that drivers don't need to use the _type field of the
new structure all the time, which will change.

Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 22 +-
.../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 11 +-
drivers/net/wireless/libertas/cfg.c | 24 +-
drivers/net/wireless/mwifiex/cfg80211.c | 30 ++-
drivers/net/wireless/orinoco/cfg.c | 11 +-
drivers/net/wireless/rndis_wlan.c | 2 +-
include/net/cfg80211.h | 65 +++---
net/mac80211/cfg.c | 43 ++--
net/mac80211/ibss.c | 21 +-
net/wireless/chan.c | 59 +----
net/wireless/core.h | 11 +-
net/wireless/ibss.c | 27 ++-
net/wireless/mesh.c | 49 ++--
net/wireless/mlme.c | 15 +-
net/wireless/nl80211.c | 253 +++++++++++----------
net/wireless/nl80211.h | 4 +-
net/wireless/rdev-ops.h | 22 +-
net/wireless/trace.h | 97 ++++----
net/wireless/wext-compat.c | 26 ++-
net/wireless/wext-sme.c | 10 +-
20 files changed, 400 insertions(+), 402 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 74091d3..c0cc2e5 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1093,15 +1093,20 @@ out:
void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
enum wmi_phy_mode mode)
{
- enum nl80211_channel_type type;
+ struct cfg80211_chan_def chandef;

ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"channel switch notify nw_type %d freq %d mode %d\n",
vif->nw_type, freq, mode);

- type = (mode == WMI_11G_HT20) ? NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT;
+ chandef.chan = ieee80211_get_channel(vif->ar->wiphy, freq);
+ if (WARN_ON(!chandef.chan))
+ return;
+
+ chandef._type = (mode == WMI_11G_HT20) ?
+ NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT;

- cfg80211_ch_switch_notify(vif->ndev, freq, type);
+ cfg80211_ch_switch_notify(vif->ndev, &chandef);
}

static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
@@ -1613,8 +1618,8 @@ static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
vif->ssid_len = ibss_param->ssid_len;
memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);

- if (ibss_param->channel)
- vif->ch_hint = ibss_param->channel->center_freq;
+ if (ibss_param->chandef.chan)
+ vif->ch_hint = ibss_param->chandef.chan->center_freq;

if (ibss_param->channel_fixed) {
/*
@@ -2856,7 +2861,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
p.ssid_len = vif->ssid_len;
memcpy(p.ssid, vif->ssid, vif->ssid_len);
p.dot11_auth_mode = vif->dot11_auth_mode;
- p.ch = cpu_to_le16(info->channel->center_freq);
+ p.ch = cpu_to_le16(info->chandef.chan->center_freq);

/* Enable uAPSD support by default */
res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
@@ -2880,8 +2885,9 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
return res;
}

- if (ath6kl_set_htcap(vif, info->channel->band,
- info->channel_type != NL80211_CHAN_NO_HT))
+ if (ath6kl_set_htcap(vif, info->chandef.chan->band,
+ cfg80211_get_chandef_type(&info->chandef)
+ != NL80211_CHAN_NO_HT))
return -EIO;

/*
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 904c941..b596ca4 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -1212,8 +1212,8 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
else
WL_CONN("No BSSID specified\n");

- if (params->channel)
- WL_CONN("channel: %d\n", params->channel->center_freq);
+ if (params->chandef.chan)
+ WL_CONN("channel: %d\n", params->chandef.chan->center_freq);
else
WL_CONN("no channel specified\n");

@@ -1286,12 +1286,12 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
}

/* Channel */
- if (params->channel) {
+ if (params->chandef.chan) {
u32 target_channel;

cfg->channel =
ieee80211_frequency_to_channel(
- params->channel->center_freq);
+ params->chandef.chan->center_freq);
if (params->channel_fixed) {
/* adding chanspec */
brcmf_ch_to_chanspec(cfg->channel,
@@ -3938,7 +3938,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
s32 bssidx = 0;

WL_TRACE("channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
- settings->channel_type, settings->beacon_interval,
+ cfg80211_get_chandef_type(&settings->chandef),
+ settings->beacon_interval,
settings->dtim_period);
WL_TRACE("ssid=%s(%d), auth_type=%d, inactivity_timeout=%d\n",
settings->ssid, settings->ssid_len, settings->auth_type,
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 1c10b54..ec36868 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -436,19 +436,19 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
*/

static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
- struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type)
+ struct cfg80211_chan_def *chandef)
{
struct lbs_private *priv = wiphy_priv(wiphy);
int ret = -ENOTSUPP;

lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
- channel->center_freq, channel_type);
+ chandef->chan->center_freq,
+ cfg80211_get_chandef_type(chandef));

- if (channel_type != NL80211_CHAN_NO_HT)
+ if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT)
goto out;

- ret = lbs_set_channel(priv, channel->hw_value);
+ ret = lbs_set_channel(priv, chandef->chan->hw_value);

out:
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -1734,7 +1734,7 @@ static void lbs_join_post(struct lbs_private *priv,
/* Fake DS channel IE */
*fake++ = WLAN_EID_DS_PARAMS;
*fake++ = 1;
- *fake++ = params->channel->hw_value;
+ *fake++ = params->chandef.chan->hw_value;
/* Fake IBSS params IE */
*fake++ = WLAN_EID_IBSS_PARAMS;
*fake++ = 2;
@@ -1755,7 +1755,7 @@ static void lbs_join_post(struct lbs_private *priv,
lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie);

bss = cfg80211_inform_bss(priv->wdev->wiphy,
- params->channel,
+ params->chandef.chan,
bssid,
0,
capability,
@@ -1833,7 +1833,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv,
cmd.bss.beaconperiod = cpu_to_le16(params->beacon_interval);
cmd.bss.ds.header.id = WLAN_EID_DS_PARAMS;
cmd.bss.ds.header.len = 1;
- cmd.bss.ds.channel = params->channel->hw_value;
+ cmd.bss.ds.channel = params->chandef.chan->hw_value;
cmd.bss.ibss.header.id = WLAN_EID_IBSS_PARAMS;
cmd.bss.ibss.header.len = 2;
cmd.bss.ibss.atimwindow = 0;
@@ -1942,7 +1942,7 @@ static int lbs_ibss_start_new(struct lbs_private *priv,
cmd.ibss.atimwindow = 0;
cmd.ds.header.id = WLAN_EID_DS_PARAMS;
cmd.ds.header.len = 1;
- cmd.ds.channel = params->channel->hw_value;
+ cmd.ds.channel = params->chandef.chan->hw_value;
/* Only v8 and below support setting probe delay */
if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8)
cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
@@ -1987,18 +1987,18 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,

lbs_deb_enter(LBS_DEB_CFG80211);

- if (!params->channel) {
+ if (!params->chandef.chan) {
ret = -ENOTSUPP;
goto out;
}

- ret = lbs_set_channel(priv, params->channel->hw_value);
+ ret = lbs_set_channel(priv, params->chandef.chan->hw_value);
if (ret)
goto out;

/* Search if someone is beaconing. This assumes that the
* bss list is populated already */
- bss = cfg80211_get_bss(wiphy, params->channel, params->bssid,
+ bss = cfg80211_get_bss(wiphy, params->chandef.chan, params->bssid,
params->ssid, params->ssid_len,
WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);

diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index f69190b..42be612 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -1291,21 +1291,23 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
return -EINVAL;
}

- bss_cfg->channel =
- (u8)ieee80211_frequency_to_channel(params->channel->center_freq);
+ bss_cfg->channel = ieee80211_frequency_to_channel(
+ params->chandef.chan->center_freq);

/* Set appropriate bands */
- if (params->channel->band == IEEE80211_BAND_2GHZ) {
+ if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) {
bss_cfg->band_cfg = BAND_CONFIG_BG;

- if (params->channel_type == NL80211_CHAN_NO_HT)
+ if (cfg80211_get_chandef_type(&params->chandef) ==
+ NL80211_CHAN_NO_HT)
config_bands = BAND_B | BAND_G;
else
config_bands = BAND_B | BAND_G | BAND_GN;
} else {
bss_cfg->band_cfg = BAND_CONFIG_A;

- if (params->channel_type == NL80211_CHAN_NO_HT)
+ if (cfg80211_get_chandef_type(&params->chandef) ==
+ NL80211_CHAN_NO_HT)
config_bands = BAND_A;
else
config_bands = BAND_AN | BAND_A;
@@ -1678,7 +1680,7 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv,
int index = 0, i;
u8 config_bands = 0;

- if (params->channel->band == IEEE80211_BAND_2GHZ) {
+ if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) {
if (!params->basic_rates) {
config_bands = BAND_B | BAND_G;
} else {
@@ -1703,10 +1705,12 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv,
}
}

- if (params->channel_type != NL80211_CHAN_NO_HT)
+ if (cfg80211_get_chandef_type(&params->chandef) !=
+ NL80211_CHAN_NO_HT)
config_bands |= BAND_GN;
} else {
- if (params->channel_type == NL80211_CHAN_NO_HT)
+ if (cfg80211_get_chandef_type(&params->chandef) !=
+ NL80211_CHAN_NO_HT)
config_bands = BAND_A;
else
config_bands = BAND_AN | BAND_A;
@@ -1723,9 +1727,10 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv,
}

adapter->sec_chan_offset =
- mwifiex_chan_type_to_sec_chan_offset(params->channel_type);
- priv->adhoc_channel =
- ieee80211_frequency_to_channel(params->channel->center_freq);
+ mwifiex_chan_type_to_sec_chan_offset(
+ cfg80211_get_chandef_type(&params->chandef));
+ priv->adhoc_channel = ieee80211_frequency_to_channel(
+ params->chandef.chan->center_freq);

wiphy_dbg(wiphy, "info: set ibss band %d, chan %d, chan offset %d\n",
config_bands, priv->adhoc_channel, adapter->sec_chan_offset);
@@ -1759,7 +1764,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,

ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid,
params->bssid, priv->bss_mode,
- params->channel, NULL, params->privacy);
+ params->chandef.chan, NULL,
+ params->privacy);
done:
if (!ret) {
cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL);
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index 7b751fb..d01edd2 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -161,24 +161,23 @@ static int orinoco_scan(struct wiphy *wiphy,
}

static int orinoco_set_monitor_channel(struct wiphy *wiphy,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type)
+ struct cfg80211_chan_def *chandef)
{
struct orinoco_private *priv = wiphy_priv(wiphy);
int err = 0;
unsigned long flags;
int channel;

- if (!chan)
+ if (!chandef->chan)
return -EINVAL;

- if (channel_type != NL80211_CHAN_NO_HT)
+ if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT)
return -EINVAL;

- if (chan->band != IEEE80211_BAND_2GHZ)
+ if (chandef->chan->band != IEEE80211_BAND_2GHZ)
return -EINVAL;

- channel = ieee80211_freq_to_dsss_chan(chan->center_freq);
+ channel = ieee80211_freq_to_dsss_chan(chandef->chan->center_freq);

if ((channel < 1) || (channel > NUM_CHANNELS) ||
!(priv->channel_mask & (1 << (channel - 1))))
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 5390af3..abe1d03 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2293,7 +2293,7 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
{
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;
- struct ieee80211_channel *channel = params->channel;
+ struct ieee80211_channel *channel = params->chandef.chan;
struct ndis_80211_ssid ssid;
enum nl80211_auth_type auth_type;
int ret, alg, length, chan = -1;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9de217e..ddcc6ca 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -306,6 +306,23 @@ struct key_params {
};

/**
+ * struct cfg80211_chan_def - channel definition
+ * @chan: the (control) channel
+ * @_type: the channel type, don't use this field,
+ * use cfg80211_get_chandef_type() if needed.
+ */
+struct cfg80211_chan_def {
+ struct ieee80211_channel *chan;
+ enum nl80211_channel_type _type;
+};
+
+static inline enum nl80211_channel_type
+cfg80211_get_chandef_type(const struct cfg80211_chan_def *chandef)
+{
+ return chandef->_type;
+}
+
+/**
* enum survey_info_flags - survey information flags
*
* @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in
@@ -426,8 +443,7 @@ struct cfg80211_beacon_data {
*
* Used to configure an AP interface.
*
- * @channel: the channel to start the AP on
- * @channel_type: the channel type to use
+ * @chandef: defines the channel to use
* @beacon: beacon data
* @beacon_interval: beacon interval
* @dtim_period: DTIM period
@@ -441,8 +457,7 @@ struct cfg80211_beacon_data {
* @inactivity_timeout: time in seconds to determine station's inactivity.
*/
struct cfg80211_ap_settings {
- struct ieee80211_channel *channel;
- enum nl80211_channel_type channel_type;
+ struct cfg80211_chan_def chandef;

struct cfg80211_beacon_data beacon;

@@ -909,8 +924,7 @@ struct mesh_config {

/**
* struct mesh_setup - 802.11s mesh setup configuration
- * @channel: the channel to start the mesh network on
- * @channel_type: the channel type to use
+ * @chandef: defines the channel to use
* @mesh_id: the mesh ID
* @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes
* @sync_method: which synchronization method to use
@@ -925,8 +939,7 @@ struct mesh_config {
* These parameters are fixed when the mesh is created.
*/
struct mesh_setup {
- struct ieee80211_channel *channel;
- enum nl80211_channel_type channel_type;
+ struct cfg80211_chan_def chandef;
const u8 *mesh_id;
u8 mesh_id_len;
u8 sync_method;
@@ -1266,8 +1279,7 @@ struct cfg80211_disassoc_request {
* @ssid_len: The length of the SSID, will always be non-zero.
* @bssid: Fixed BSSID requested, maybe be %NULL, if set do not
* search for IBSSs with a different BSSID.
- * @channel: The channel to use if no IBSS can be found to join.
- * @channel_type: channel type (HT mode)
+ * @chandef: defines the channel to use if no other IBSS to join can be found
* @channel_fixed: The channel should be fixed -- do not search for
* IBSSs to join on other channels.
* @ie: information element(s) to include in the beacon
@@ -1285,8 +1297,7 @@ struct cfg80211_disassoc_request {
struct cfg80211_ibss_params {
u8 *ssid;
u8 *bssid;
- struct ieee80211_channel *channel;
- enum nl80211_channel_type channel_type;
+ struct cfg80211_chan_def chandef;
u8 *ie;
u8 ssid_len, ie_len;
u16 beacon_interval;
@@ -1728,8 +1739,7 @@ struct cfg80211_ops {
struct ieee80211_channel *chan);

int (*set_monitor_channel)(struct wiphy *wiphy,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type);
+ struct cfg80211_chan_def *chandef);

int (*scan)(struct wiphy *wiphy,
struct cfg80211_scan_request *request);
@@ -1855,10 +1865,9 @@ struct cfg80211_ops {
void (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev,
u32 sset, u8 *data);

- struct ieee80211_channel *
- (*get_channel)(struct wiphy *wiphy,
+ int (*get_channel)(struct wiphy *wiphy,
struct wireless_dev *wdev,
- enum nl80211_channel_type *type);
+ struct cfg80211_chan_def *chandef);

int (*start_p2p_device)(struct wiphy *wiphy,
struct wireless_dev *wdev);
@@ -2466,8 +2475,7 @@ struct wireless_dev {
spinlock_t event_lock;

struct cfg80211_internal_bss *current_bss; /* associated / joined */
- struct ieee80211_channel *preset_chan;
- enum nl80211_channel_type preset_chantype;
+ struct cfg80211_chan_def preset_chandef;

/* for AP and mesh channel tracking */
struct ieee80211_channel *channel;
@@ -3563,28 +3571,25 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
int freq, int sig_dbm);

/**
- * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used
+ * cfg80211_reg_can_beacon - check if beaconing is allowed
* @wiphy: the wiphy
- * @chan: main channel
- * @channel_type: HT mode
+ * @chandef: the channel definition
*
* This function returns true if there is no secondary channel or the secondary
- * channel can be used for beaconing (i.e. is not a radar channel etc.)
+ * channel(s) can be used for beaconing (i.e. is not a radar channel etc.)
*/
-bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type);
+bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef);

/*
* cfg80211_ch_switch_notify - update wdev channel and notify userspace
* @dev: the device which switched channels
- * @freq: new channel frequency (in MHz)
- * @type: channel type
+ * @chandef: the new channel definition
*
* Acquires wdev_lock, so must only be called from sleepable driver context!
*/
-void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
- enum nl80211_channel_type type);
+void cfg80211_ch_switch_notify(struct net_device *dev,
+ struct cfg80211_chan_def *chandef);

/**
* ieee80211_operating_class_to_band - convert operating class to band
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 63f55d8..4327443 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -738,14 +738,16 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
}

static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type)
+ struct cfg80211_chan_def *chandef)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata;
+ enum nl80211_channel_type channel_type;
int ret = 0;

- if (local->monitor_channel == chan &&
+ channel_type = cfg80211_get_chandef_type(chandef);
+
+ if (local->monitor_channel == chandef->chan &&
local->monitor_channel_type == channel_type)
return 0;

@@ -757,17 +759,17 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
if (sdata) {
ieee80211_vif_release_channel(sdata);
ret = ieee80211_vif_use_channel(
- sdata, chan, channel_type,
+ sdata, chandef->chan, channel_type,
IEEE80211_CHANCTX_EXCLUSIVE);
}
} else if (local->open_count == local->monitors) {
- local->_oper_channel = chan;
+ local->_oper_channel = chandef->chan;
local->_oper_channel_type = channel_type;
ieee80211_hw_config(local, 0);
}

if (ret == 0) {
- local->monitor_channel = chan;
+ local->monitor_channel = chandef->chan;
local->monitor_channel_type = channel_type;
}
mutex_unlock(&local->iflist_mtx);
@@ -891,9 +893,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
sdata->smps_mode = IEEE80211_SMPS_OFF;
sdata->needed_rx_chains = sdata->local->rx_chains;

- err = ieee80211_vif_use_channel(sdata, params->channel,
- params->channel_type,
- IEEE80211_CHANCTX_SHARED);
+ err = ieee80211_vif_use_channel(
+ sdata, params->chandef.chan,
+ cfg80211_get_chandef_type(&params->chandef),
+ IEEE80211_CHANCTX_SHARED);
if (err)
return err;

@@ -1734,9 +1737,10 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
sdata->smps_mode = IEEE80211_SMPS_OFF;
sdata->needed_rx_chains = sdata->local->rx_chains;

- err = ieee80211_vif_use_channel(sdata, setup->channel,
- setup->channel_type,
- IEEE80211_CHANCTX_SHARED);
+ err = ieee80211_vif_use_channel(
+ sdata, setup->chandef.chan,
+ cfg80211_get_chandef_type(&setup->chandef),
+ IEEE80211_CHANCTX_SHARED);
if (err)
return err;

@@ -3137,23 +3141,24 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
return 0;
}

-static struct ieee80211_channel *
-ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
- enum nl80211_channel_type *type)
+static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct cfg80211_chan_def *chandef)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct ieee80211_chanctx_conf *chanctx_conf;
- struct ieee80211_channel *chan = NULL;
+ int ret = -ENODATA;

rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (chanctx_conf) {
- *type = chanctx_conf->channel_type;
- chan = chanctx_conf->channel;
+ chandef->chan = chanctx_conf->channel;
+ chandef->_type = chanctx_conf->channel_type;
+ ret = 0;
}
rcu_read_unlock();

- return chan;
+ return ret;
}

#ifdef CONFIG_PM
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index c7386b2..b7bfb4f 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -51,7 +51,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
struct cfg80211_bss *bss;
u32 bss_change;
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
- enum nl80211_channel_type channel_type;
+ struct cfg80211_chan_def chandef;

lockdep_assert_held(&ifibss->mtx);

@@ -79,12 +79,13 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,

sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;

- channel_type = ifibss->channel_type;
- if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
- channel_type = NL80211_CHAN_HT20;
+ chandef.chan = chan;
+ chandef._type = ifibss->channel_type;
+ if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef))
+ chandef._type = NL80211_CHAN_HT20;

ieee80211_vif_release_channel(sdata);
- if (ieee80211_vif_use_channel(sdata, chan, channel_type,
+ if (ieee80211_vif_use_channel(sdata, chan, chandef._type,
ifibss->fixed_channel ?
IEEE80211_CHANCTX_SHARED :
IEEE80211_CHANCTX_EXCLUSIVE)) {
@@ -158,7 +159,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
ifibss->ie, ifibss->ie_len);

/* add HT capability and information IEs */
- if (channel_type && sband->ht_cap.ht_supported) {
+ if (chandef._type != NL80211_CHAN_NO_HT &&
+ sband->ht_cap.ht_supported) {
pos = skb_put(skb, 4 +
sizeof(struct ieee80211_ht_cap) +
sizeof(struct ieee80211_ht_operation));
@@ -170,7 +172,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
* keep them at 0
*/
pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
- chan, channel_type, 0);
+ chan, chandef._type, 0);
}

if (local->hw.queues >= IEEE80211_NUM_ACS) {
@@ -1095,8 +1097,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,

sdata->vif.bss_conf.beacon_int = params->beacon_interval;

- sdata->u.ibss.channel = params->channel;
- sdata->u.ibss.channel_type = params->channel_type;
+ sdata->u.ibss.channel = params->chandef.chan;
+ sdata->u.ibss.channel_type =
+ cfg80211_get_chandef_type(&params->chandef);
sdata->u.ibss.fixed_channel = params->channel_fixed;

if (params->ie) {
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 48febd2..e834422 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -11,51 +11,15 @@
#include "core.h"
#include "rdev-ops.h"

-struct ieee80211_channel *
-rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
- int freq, enum nl80211_channel_type channel_type)
-{
- struct ieee80211_channel *chan;
- struct ieee80211_sta_ht_cap *ht_cap;
-
- chan = ieee80211_get_channel(&rdev->wiphy, freq);
-
- /* Primary channel not allowed */
- if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
- return NULL;
-
- if (channel_type == NL80211_CHAN_HT40MINUS &&
- chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
- return NULL;
- else if (channel_type == NL80211_CHAN_HT40PLUS &&
- chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
- return NULL;
-
- ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
-
- if (channel_type != NL80211_CHAN_NO_HT) {
- if (!ht_cap->ht_supported)
- return NULL;
-
- if (channel_type != NL80211_CHAN_HT20 &&
- (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
- ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT))
- return NULL;
- }
-
- return chan;
-}
-
-bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type)
+bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef)
{
struct ieee80211_channel *sec_chan;
int diff;

- trace_cfg80211_can_beacon_sec_chan(wiphy, chan, channel_type);
+ trace_cfg80211_reg_can_beacon(wiphy, chandef);

- switch (channel_type) {
+ switch (chandef->_type) {
case NL80211_CHAN_HT40PLUS:
diff = 20;
break;
@@ -67,7 +31,8 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
return true;
}

- sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff);
+ sec_chan = ieee80211_get_channel(wiphy,
+ chandef->chan->center_freq + diff);
if (!sec_chan) {
trace_cfg80211_return_bool(false);
return false;
@@ -84,23 +49,17 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
trace_cfg80211_return_bool(true);
return true;
}
-EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
+EXPORT_SYMBOL(cfg80211_reg_can_beacon);

int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
- int freq, enum nl80211_channel_type chantype)
+ struct cfg80211_chan_def *chandef)
{
- struct ieee80211_channel *chan;
-
if (!rdev->ops->set_monitor_channel)
return -EOPNOTSUPP;
if (!cfg80211_has_monitors_only(rdev))
return -EBUSY;

- chan = rdev_freq_to_chan(rdev, freq, chantype);
- if (!chan)
- return -EINVAL;
-
- return rdev_set_monitor_channel(rdev, chan, chantype);
+ return rdev_set_monitor_channel(rdev, chandef);
}

void
diff --git a/net/wireless/core.h b/net/wireless/core.h
index b0a09cf..6183a0d 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -309,9 +309,9 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
const struct mesh_config *conf);
int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev);
-int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev, int freq,
- enum nl80211_channel_type channel_type);
+int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ struct cfg80211_chan_def *chandef);

/* AP */
int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
@@ -470,11 +470,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
struct ieee80211_channel **chan,
enum cfg80211_chan_mode *chanmode);

-struct ieee80211_channel *
-rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
- int freq, enum nl80211_channel_type channel_type);
int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
- int freq, enum nl80211_channel_type chantype);
+ struct cfg80211_chan_def *chandef);

int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
const u8 *rates, unsigned int n_rates,
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 27941d5..ccc8865 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -100,9 +100,9 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
* 11a for maximum compatibility.
*/
struct ieee80211_supported_band *sband =
- rdev->wiphy.bands[params->channel->band];
+ rdev->wiphy.bands[params->chandef.chan->band];
int j;
- u32 flag = params->channel->band == IEEE80211_BAND_5GHZ ?
+ u32 flag = params->chandef.chan->band == IEEE80211_BAND_5GHZ ?
IEEE80211_RATE_MANDATORY_A :
IEEE80211_RATE_MANDATORY_B;

@@ -118,11 +118,11 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,

wdev->ibss_fixed = params->channel_fixed;
#ifdef CONFIG_CFG80211_WEXT
- wdev->wext.ibss.channel = params->channel;
+ wdev->wext.ibss.chandef = params->chandef;
#endif
wdev->sme_state = CFG80211_SME_CONNECTING;

- err = cfg80211_can_use_chan(rdev, wdev, params->channel,
+ err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan,
params->channel_fixed
? CHAN_MODE_SHARED
: CHAN_MODE_EXCLUSIVE);
@@ -251,7 +251,9 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
wdev->wext.ibss.beacon_interval = 100;

/* try to find an IBSS channel if none requested ... */
- if (!wdev->wext.ibss.channel) {
+ if (!wdev->wext.ibss.chandef.chan) {
+ wdev->wext.ibss.chandef._type = NL80211_CHAN_NO_HT;
+
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan;
@@ -266,15 +268,15 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
continue;
if (chan->flags & IEEE80211_CHAN_DISABLED)
continue;
- wdev->wext.ibss.channel = chan;
+ wdev->wext.ibss.chandef.chan = chan;
break;
}

- if (wdev->wext.ibss.channel)
+ if (wdev->wext.ibss.chandef.chan)
break;
}

- if (!wdev->wext.ibss.channel)
+ if (!wdev->wext.ibss.chandef.chan)
return -EINVAL;
}

@@ -336,7 +338,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
return -EINVAL;
}

- if (wdev->wext.ibss.channel == chan)
+ if (wdev->wext.ibss.chandef.chan == chan)
return 0;

wdev_lock(wdev);
@@ -349,7 +351,8 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
return err;

if (chan) {
- wdev->wext.ibss.channel = chan;
+ wdev->wext.ibss.chandef.chan = chan;
+ wdev->wext.ibss.chandef._type = NL80211_CHAN_NO_HT;
wdev->wext.ibss.channel_fixed = true;
} else {
/* cfg80211_ibss_wext_join will pick one if needed */
@@ -379,8 +382,8 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
wdev_lock(wdev);
if (wdev->current_bss)
chan = wdev->current_bss->pub.channel;
- else if (wdev->wext.ibss.channel)
- chan = wdev->wext.ibss.channel;
+ else if (wdev->wext.ibss.chandef.chan)
+ chan = wdev->wext.ibss.chandef.chan;
wdev_unlock(wdev);

if (chan) {
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 966cfc4..12b5a57 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -73,8 +73,6 @@ const struct mesh_config default_mesh_config = {

const struct mesh_setup default_mesh_setup = {
/* cfg80211_join_mesh() will pick a channel if needed */
- .channel = NULL,
- .channel_type = NL80211_CHAN_NO_HT,
.sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
.path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP,
.path_metric = IEEE80211_PATH_METRIC_AIRTIME,
@@ -111,13 +109,12 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
if (!rdev->ops->join_mesh)
return -EOPNOTSUPP;

- if (!setup->channel) {
+ if (!setup->chandef.chan) {
/* if no channel explicitly given, use preset channel */
- setup->channel = wdev->preset_chan;
- setup->channel_type = wdev->preset_chantype;
+ setup->chandef = wdev->preset_chandef;
}

- if (!setup->channel) {
+ if (!setup->chandef.chan) {
/* if we don't have that either, use the first usable channel */
enum ieee80211_band band;

@@ -137,26 +134,25 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
IEEE80211_CHAN_DISABLED |
IEEE80211_CHAN_RADAR))
continue;
- setup->channel = chan;
+ setup->chandef.chan = chan;
break;
}

- if (setup->channel)
+ if (setup->chandef.chan)
break;
}

/* no usable channel ... */
- if (!setup->channel)
+ if (!setup->chandef.chan)
return -EINVAL;

- setup->channel_type = NL80211_CHAN_NO_HT;
+ setup->chandef._type = NL80211_CHAN_NO_HT;
}

- if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, setup->channel,
- setup->channel_type))
+ if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
return -EINVAL;

- err = cfg80211_can_use_chan(rdev, wdev, setup->channel,
+ err = cfg80211_can_use_chan(rdev, wdev, setup->chandef.chan,
CHAN_MODE_SHARED);
if (err)
return err;
@@ -165,7 +161,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
if (!err) {
memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
wdev->mesh_id_len = setup->mesh_id_len;
- wdev->channel = setup->channel;
+ wdev->channel = setup->chandef.chan;
}

return err;
@@ -188,20 +184,12 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
return err;
}

-int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev, int freq,
- enum nl80211_channel_type channel_type)
+int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ struct cfg80211_chan_def *chandef)
{
- struct ieee80211_channel *channel;
int err;

- channel = rdev_freq_to_chan(rdev, freq, channel_type);
- if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
- channel,
- channel_type)) {
- return -EINVAL;
- }
-
/*
* Workaround for libertas (only!), it puts the interface
* into mesh mode but doesn't implement join_mesh. Instead,
@@ -210,21 +198,21 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
* compatible with 802.11 mesh.
*/
if (rdev->ops->libertas_set_mesh_channel) {
- if (channel_type != NL80211_CHAN_NO_HT)
+ if (chandef->_type != NL80211_CHAN_NO_HT)
return -EINVAL;

if (!netif_running(wdev->netdev))
return -ENETDOWN;

- err = cfg80211_can_use_chan(rdev, wdev, channel,
+ err = cfg80211_can_use_chan(rdev, wdev, chandef->chan,
CHAN_MODE_SHARED);
if (err)
return err;

err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
- channel);
+ chandef->chan);
if (!err)
- wdev->channel = channel;
+ wdev->channel = chandef->chan;

return err;
}
@@ -232,8 +220,7 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
if (wdev->mesh_id_len)
return -EBUSY;

- wdev->preset_chan = channel;
- wdev->preset_chantype = channel_type;
+ wdev->preset_chandef = *chandef;
return 0;
}

diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index a9646b5..5e8123e 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -988,15 +988,14 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
}
EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);

-void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
- enum nl80211_channel_type type)
+void cfg80211_ch_switch_notify(struct net_device *dev,
+ struct cfg80211_chan_def *chandef)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- struct ieee80211_channel *chan;

- trace_cfg80211_ch_switch_notify(dev, freq, type);
+ trace_cfg80211_ch_switch_notify(dev, chandef);

wdev_lock(wdev);

@@ -1004,12 +1003,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
wdev->iftype != NL80211_IFTYPE_P2P_GO))
goto out;

- chan = rdev_freq_to_chan(rdev, freq, type);
- if (WARN_ON(!chan))
- goto out;
-
- wdev->channel = chan;
- nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL);
+ wdev->channel = chandef->chan;
+ nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
out:
wdev_unlock(wdev);
return;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 7db26b6..bed5a0e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1381,30 +1381,82 @@ static bool nl80211_valid_channel_type(struct genl_info *info,
return true;
}

+static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
+ struct genl_info *info,
+ struct cfg80211_chan_def *chandef)
+{
+ struct ieee80211_sta_ht_cap *ht_cap;
+ struct ieee80211_channel *sc;
+ u32 control_freq;
+ int offs;
+
+ if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
+ return -EINVAL;
+
+ control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+
+ chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq);
+ chandef->_type = NL80211_CHAN_NO_HT;
+
+ if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
+ !nl80211_valid_channel_type(info, &chandef->_type))
+ return -EINVAL;
+
+ /* Primary channel not allowed */
+ if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED)
+ return -EINVAL;
+
+ ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap;
+
+ switch (chandef->_type) {
+ case NL80211_CHAN_NO_HT:
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ if (chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
+ return -EINVAL;
+ offs = -20;
+ /* fall through */
+ case NL80211_CHAN_HT40PLUS:
+ if (chandef->_type == NL80211_CHAN_HT40PLUS) {
+ if (chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
+ return -EINVAL;
+ offs = 20;
+ }
+ if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
+ ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
+ return -EINVAL;
+
+ sc = ieee80211_get_channel(&rdev->wiphy,
+ chandef->chan->center_freq + offs);
+ if (!sc || sc->flags & IEEE80211_CHAN_DISABLED)
+ return -EINVAL;
+ /* fall through */
+ case NL80211_CHAN_HT20:
+ if (!ht_cap->ht_supported)
+ return -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct genl_info *info)
{
- struct ieee80211_channel *channel;
- enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
- u32 freq;
+ struct cfg80211_chan_def chandef;
int result;
enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;

if (wdev)
iftype = wdev->iftype;

- if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
- return -EINVAL;
-
if (!nl80211_can_set_dev_channel(wdev))
return -EOPNOTSUPP;

- if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
- !nl80211_valid_channel_type(info, &channel_type))
- return -EINVAL;
-
- freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+ result = nl80211_parse_chandef(rdev, info, &chandef);
+ if (result)
+ return result;

mutex_lock(&rdev->devlist_mtx);
switch (iftype) {
@@ -1414,22 +1466,18 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
result = -EBUSY;
break;
}
- channel = rdev_freq_to_chan(rdev, freq, channel_type);
- if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
- channel,
- channel_type)) {
+ if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef)) {
result = -EINVAL;
break;
}
- wdev->preset_chan = channel;
- wdev->preset_chantype = channel_type;
+ wdev->preset_chandef = chandef;
result = 0;
break;
case NL80211_IFTYPE_MESH_POINT:
- result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type);
+ result = cfg80211_set_mesh_channel(rdev, wdev, &chandef);
break;
case NL80211_IFTYPE_MONITOR:
- result = cfg80211_set_monitor_channel(rdev, freq, channel_type);
+ result = cfg80211_set_monitor_channel(rdev, &chandef);
break;
default:
result = -EINVAL;
@@ -1749,6 +1797,17 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
((u64)wiphy_to_dev(wdev->wiphy)->wiphy_idx << 32);
}

+static int nl80211_send_chandef(struct sk_buff *msg,
+ struct cfg80211_chan_def *chandef)
+{
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
+ chandef->chan->center_freq))
+ return -ENOBUFS;
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, chandef->_type))
+ return -ENOBUFS;
+ return 0;
+}
+
static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev)
@@ -1775,16 +1834,14 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
goto nla_put_failure;

if (rdev->ops->get_channel) {
- struct ieee80211_channel *chan;
- enum nl80211_channel_type channel_type;
-
- chan = rdev_get_channel(rdev, wdev, &channel_type);
- if (chan &&
- (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
- chan->center_freq) ||
- nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
- channel_type)))
- goto nla_put_failure;
+ int ret;
+ struct cfg80211_chan_def chandef;
+
+ ret = rdev_get_channel(rdev, wdev, &chandef);
+ if (ret == 0) {
+ if (nl80211_send_chandef(msg, &chandef))
+ goto nla_put_failure;
+ }
}

if (wdev->ssid_len) {
@@ -2492,11 +2549,10 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
wdev->iftype != NL80211_IFTYPE_P2P_GO)
continue;

- if (!wdev->preset_chan)
+ if (!wdev->preset_chandef.chan)
continue;

- params->channel = wdev->preset_chan;
- params->channel_type = wdev->preset_chantype;
+ params->chandef = wdev->preset_chandef;
ret = true;
break;
}
@@ -2618,30 +2674,19 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
}

if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
- enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
-
- if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
- !nl80211_valid_channel_type(info, &channel_type))
- return -EINVAL;
-
- params.channel = rdev_freq_to_chan(rdev,
- nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
- channel_type);
- if (!params.channel)
- return -EINVAL;
- params.channel_type = channel_type;
- } else if (wdev->preset_chan) {
- params.channel = wdev->preset_chan;
- params.channel_type = wdev->preset_chantype;
+ err = nl80211_parse_chandef(rdev, info, &params.chandef);
+ if (err)
+ return err;
+ } else if (wdev->preset_chandef.chan) {
+ params.chandef = wdev->preset_chandef;
} else if (!nl80211_get_ap_channel(rdev, &params))
return -EINVAL;

- if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel,
- params.channel_type))
+ if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
return -EINVAL;

mutex_lock(&rdev->devlist_mtx);
- err = cfg80211_can_use_chan(rdev, wdev, params.channel,
+ err = cfg80211_can_use_chan(rdev, wdev, params.chandef.chan,
CHAN_MODE_SHARED);
mutex_unlock(&rdev->devlist_mtx);

@@ -2650,10 +2695,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)

err = rdev_start_ap(rdev, dev, &params);
if (!err) {
- wdev->preset_chan = params.channel;
- wdev->preset_chantype = params.channel_type;
+ wdev->preset_chandef = params.chandef;
wdev->beacon_interval = params.beacon_interval;
- wdev->channel = params.channel;
+ wdev->channel = params.chandef.chan;
wdev->ssid_len = params.ssid_len;
memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
}
@@ -5354,8 +5398,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
return -EINVAL;

- if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
- !info->attrs[NL80211_ATTR_SSID] ||
+ if (!info->attrs[NL80211_ATTR_SSID] ||
!nla_len(info->attrs[NL80211_ATTR_SSID]))
return -EINVAL;

@@ -5390,34 +5433,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}

- if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
- enum nl80211_channel_type channel_type;
-
- if (!nl80211_valid_channel_type(info, &channel_type))
- return -EINVAL;
-
- if (channel_type != NL80211_CHAN_NO_HT &&
- !(wiphy->features & NL80211_FEATURE_HT_IBSS))
- return -EINVAL;
-
- ibss.channel_type = channel_type;
- } else {
- ibss.channel_type = NL80211_CHAN_NO_HT;
- }
-
- ibss.channel = rdev_freq_to_chan(rdev,
- nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
- ibss.channel_type);
- if (!ibss.channel ||
- ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
- ibss.channel->flags & IEEE80211_CHAN_DISABLED)
- return -EINVAL;
+ err = nl80211_parse_chandef(rdev, info, &ibss.chandef);
+ if (err)
+ return err;

- /* Both channels should be able to initiate communication */
- if ((ibss.channel_type == NL80211_CHAN_HT40PLUS ||
- ibss.channel_type == NL80211_CHAN_HT40MINUS) &&
- !cfg80211_can_beacon_sec_chan(&rdev->wiphy, ibss.channel,
- ibss.channel_type))
+ if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef))
return -EINVAL;

ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
@@ -5429,7 +5449,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
int n_rates =
nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
struct ieee80211_supported_band *sband =
- wiphy->bands[ibss.channel->band];
+ wiphy->bands[ibss.chandef.chan->band];

err = ieee80211_get_ratemask(sband, rates, n_rates,
&ibss.basic_rates);
@@ -5451,7 +5471,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
if (IS_ERR(connkeys))
return PTR_ERR(connkeys);

- if ((ibss.channel_type != NL80211_CHAN_NO_HT) && no_ht) {
+ if ((ibss.chandef._type != NL80211_CHAN_NO_HT) && no_ht) {
kfree(connkeys);
return -EINVAL;
}
@@ -5972,11 +5992,11 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct wireless_dev *wdev = info->user_ptr[1];
- struct ieee80211_channel *chan;
+ struct cfg80211_chan_def chandef;
struct sk_buff *msg;
void *hdr;
u64 cookie;
- u32 freq, duration;
+ u32 duration;
int err;

if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
@@ -5997,14 +6017,9 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
duration > rdev->wiphy.max_remain_on_channel_duration)
return -EINVAL;

- if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
- !nl80211_valid_channel_type(info, NULL))
- return -EINVAL;
-
- freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
- chan = rdev_freq_to_chan(rdev, freq, NL80211_CHAN_NO_HT);
- if (chan == NULL)
- return -EINVAL;
+ err = nl80211_parse_chandef(rdev, info, &chandef);
+ if (err)
+ return err;

msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
@@ -6018,7 +6033,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
goto free_msg;
}

- err = rdev_remain_on_channel(rdev, wdev, chan, duration, &cookie);
+ err = rdev_remain_on_channel(rdev, wdev, chandef.chan,
+ duration, &cookie);

if (err)
goto free_msg;
@@ -6237,8 +6253,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct wireless_dev *wdev = info->user_ptr[1];
- struct ieee80211_channel *chan;
- u32 freq;
+ struct cfg80211_chan_def chandef;
int err;
void *hdr = NULL;
u64 cookie;
@@ -6248,8 +6263,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)

dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK];

- if (!info->attrs[NL80211_ATTR_FRAME] ||
- !info->attrs[NL80211_ATTR_WIPHY_FREQ])
+ if (!info->attrs[NL80211_ATTR_FRAME])
return -EINVAL;

if (!rdev->ops->mgmt_tx)
@@ -6284,10 +6298,6 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)

}

- if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
- !nl80211_valid_channel_type(info, NULL))
- return -EINVAL;
-
offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];

if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
@@ -6295,10 +6305,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)

no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);

- freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
- chan = rdev_freq_to_chan(rdev, freq, NL80211_CHAN_NO_HT);
- if (chan == NULL)
- return -EINVAL;
+ err = nl80211_parse_chandef(rdev, info, &chandef);
+ if (err)
+ return err;

if (!dont_wait_for_ack) {
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
@@ -6314,7 +6323,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
}
}

- err = cfg80211_mlme_mgmt_tx(rdev, wdev, chan, offchan, wait,
+ err = cfg80211_mlme_mgmt_tx(rdev, wdev, chandef.chan, offchan, wait,
nla_data(info->attrs[NL80211_ATTR_FRAME]),
nla_len(info->attrs[NL80211_ATTR_FRAME]),
no_cck, dont_wait_for_ack, &cookie);
@@ -6578,21 +6587,12 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
}

if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
- enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
-
- if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
- !nl80211_valid_channel_type(info, &channel_type))
- return -EINVAL;
-
- setup.channel = rdev_freq_to_chan(rdev,
- nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
- channel_type);
- if (!setup.channel)
- return -EINVAL;
- setup.channel_type = channel_type;
+ err = nl80211_parse_chandef(rdev, info, &setup.chandef);
+ if (err)
+ return err;
} else {
/* cfg80211_join_mesh() will sort it out */
- setup.channel = NULL;
+ setup.chandef.chan = NULL;
}

return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
@@ -8824,8 +8824,8 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
}

void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, int freq,
- enum nl80211_channel_type type, gfp_t gfp)
+ struct net_device *netdev,
+ struct cfg80211_chan_def *chandef, gfp_t gfp)
{
struct sk_buff *msg;
void *hdr;
@@ -8840,9 +8840,10 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
return;
}

- if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
- nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
- nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, type))
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
+ goto nla_put_failure;
+
+ if (nl80211_send_chandef(msg, chandef))
goto nla_put_failure;

genlmsg_end(msg, hdr);
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 7adbd76..2acba847 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -127,8 +127,8 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
const u8 *bssid, bool preauth, gfp_t gfp);

void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
- struct net_device *dev, int freq,
- enum nl80211_channel_type type, gfp_t gfp);
+ struct net_device *dev,
+ struct cfg80211_chan_def *chandef, gfp_t gfp);

bool nl80211_unexpected_frame(struct net_device *dev,
const u8 *addr, gfp_t gfp);
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index ee54a5a..6c0c819 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -359,12 +359,11 @@ rdev_libertas_set_mesh_channel(struct cfg80211_registered_device *rdev,

static inline int
rdev_set_monitor_channel(struct cfg80211_registered_device *rdev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type)
+ struct cfg80211_chan_def *chandef)
{
int ret;
- trace_rdev_set_monitor_channel(&rdev->wiphy, chan, channel_type);
- ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, channel_type);
+ trace_rdev_set_monitor_channel(&rdev->wiphy, chandef);
+ ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chandef);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
@@ -844,14 +843,17 @@ static inline void rdev_get_et_strings(struct cfg80211_registered_device *rdev,
trace_rdev_return_void(&rdev->wiphy);
}

-static inline struct ieee80211_channel
-*rdev_get_channel(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev, enum nl80211_channel_type *type)
+static inline int
+rdev_get_channel(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ struct cfg80211_chan_def *chandef)
{
- struct ieee80211_channel *ret;
+ int ret;
+
trace_rdev_get_channel(&rdev->wiphy, wdev);
- ret = rdev->ops->get_channel(&rdev->wiphy, wdev, type);
- trace_rdev_return_channel(&rdev->wiphy, ret, *type);
+ ret = rdev->ops->get_channel(&rdev->wiphy, wdev, chandef);
+ trace_rdev_return_chandef(&rdev->wiphy, ret, chandef);
+
return ret;
}

diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 0128307..d3906db 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -126,6 +126,26 @@
#define CHAN_PR_FMT ", band: %d, freq: %u"
#define CHAN_PR_ARG __entry->band, __entry->center_freq

+#define CHAN_DEF_ENTRY __field(enum ieee80211_band, band) \
+ __field(u16, center_freq) \
+ __field(u32, channel_type)
+#define CHAN_DEF_ASSIGN(chandef) \
+ do { \
+ if ((chandef)->chan) { \
+ __entry->band = (chandef)->chan->band; \
+ __entry->center_freq = \
+ (chandef)->chan->center_freq; \
+ __entry->channel_type = (chandef)->_type; \
+ } else { \
+ __entry->band = 0; \
+ __entry->center_freq = 0; \
+ __entry->channel_type = 0; \
+ } \
+ } while (0)
+#define CHAN_DEF_PR_FMT ", band: %d, freq: %u, chantype: %d"
+#define CHAN_DEF_PR_ARG __entry->band, __entry->center_freq, \
+ __entry->channel_type
+
#define SINFO_ENTRY __field(int, generation) \
__field(u32, connected_time) \
__field(u32, inactive_time) \
@@ -433,7 +453,7 @@ TRACE_EVENT(rdev_start_ap,
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
- CHAN_ENTRY
+ CHAN_DEF_ENTRY
__field(int, beacon_interval)
__field(int, dtim_period)
__array(char, ssid, IEEE80211_MAX_SSID_LEN + 1)
@@ -446,7 +466,7 @@ TRACE_EVENT(rdev_start_ap,
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
- CHAN_ASSIGN(settings->channel);
+ CHAN_DEF_ASSIGN(&settings->chandef);
__entry->beacon_interval = settings->beacon_interval;
__entry->dtim_period = settings->dtim_period;
__entry->hidden_ssid = settings->hidden_ssid;
@@ -458,10 +478,10 @@ TRACE_EVENT(rdev_start_ap,
memcpy(__entry->ssid, settings->ssid, settings->ssid_len);
),
TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", AP settings - ssid: %s, "
- CHAN_PR_FMT ", beacon interval: %d, dtim period: %d, "
+ CHAN_DEF_PR_FMT ", beacon interval: %d, dtim period: %d, "
"hidden ssid: %d, wpa versions: %u, privacy: %s, "
"auth type: %d, inactivity timeout: %d",
- WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_PR_ARG,
+ WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_DEF_PR_ARG,
__entry->beacon_interval, __entry->dtim_period,
__entry->hidden_ssid, __entry->wpa_ver,
BOOL_TO_STR(__entry->privacy), __entry->auth_type,
@@ -933,21 +953,19 @@ TRACE_EVENT(rdev_libertas_set_mesh_channel,
);

TRACE_EVENT(rdev_set_monitor_channel,
- TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *chan,
- enum nl80211_channel_type chan_type),
- TP_ARGS(wiphy, chan, chan_type),
+ TP_PROTO(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef),
+ TP_ARGS(wiphy, chandef),
TP_STRUCT__entry(
WIPHY_ENTRY
- CHAN_ENTRY
- __field(enum nl80211_channel_type, chan_type)
+ CHAN_DEF_ENTRY
),
TP_fast_assign(
WIPHY_ASSIGN;
- CHAN_ASSIGN(chan);
- __entry->chan_type = chan_type;
+ CHAN_DEF_ASSIGN(chandef);
),
- TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel type : %d",
- WIPHY_PR_ARG, CHAN_PR_ARG, __entry->chan_type)
+ TP_printk(WIPHY_PR_FMT CHAN_DEF_PR_FMT,
+ WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
);

TRACE_EVENT(rdev_auth,
@@ -1713,22 +1731,22 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel,
TP_ARGS(wiphy, wdev)
);

-TRACE_EVENT(rdev_return_channel,
- TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *chan,
- enum nl80211_channel_type type),
- TP_ARGS(wiphy, chan, type),
+TRACE_EVENT(rdev_return_chandef,
+ TP_PROTO(struct wiphy *wiphy, int ret,
+ struct cfg80211_chan_def *chandef),
+ TP_ARGS(wiphy, ret, chandef),
TP_STRUCT__entry(
WIPHY_ENTRY
- CHAN_ENTRY
- __field(enum nl80211_channel_type, type)
+ __field(int, ret)
+ CHAN_DEF_ENTRY
),
TP_fast_assign(
WIPHY_ASSIGN;
- CHAN_ASSIGN(chan);
- __entry->type = type;
+ CHAN_DEF_ASSIGN(chandef);
+ __entry->ret = ret;
),
- TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel type: %d",
- WIPHY_PR_ARG, CHAN_PR_ARG, __entry->type)
+ TP_printk(WIPHY_PR_FMT CHAN_DEF_PR_FMT ", ret: %d",
+ WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->ret)
);

DEFINE_EVENT(wiphy_wdev_evt, rdev_start_p2p_device,
@@ -1992,40 +2010,35 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify,
NETDEV_PR_ARG, __entry->rssi_event)
);

-TRACE_EVENT(cfg80211_can_beacon_sec_chan,
- TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type),
- TP_ARGS(wiphy, channel, channel_type),
+TRACE_EVENT(cfg80211_reg_can_beacon,
+ TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
+ TP_ARGS(wiphy, chandef),
TP_STRUCT__entry(
WIPHY_ENTRY
- CHAN_ENTRY
- __field(enum nl80211_channel_type, channel_type)
+ CHAN_DEF_ENTRY
),
TP_fast_assign(
WIPHY_ASSIGN;
- CHAN_ASSIGN(channel);
- __entry->channel_type = channel_type;
+ CHAN_DEF_ASSIGN(chandef);
),
- TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel_type: %d",
- WIPHY_PR_ARG, CHAN_PR_ARG, __entry->channel_type)
+ TP_printk(WIPHY_PR_FMT CHAN_DEF_PR_FMT,
+ WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
);

TRACE_EVENT(cfg80211_ch_switch_notify,
- TP_PROTO(struct net_device *netdev, int freq,
- enum nl80211_channel_type type),
- TP_ARGS(netdev, freq, type),
+ TP_PROTO(struct net_device *netdev,
+ struct cfg80211_chan_def *chandef),
+ TP_ARGS(netdev, chandef),
TP_STRUCT__entry(
NETDEV_ENTRY
- __field(int, freq)
- __field(enum nl80211_channel_type, type)
+ CHAN_DEF_ENTRY
),
TP_fast_assign(
NETDEV_ASSIGN;
- __entry->freq = freq;
- __entry->type = type;
+ CHAN_DEF_ASSIGN(chandef);
),
- TP_printk(NETDEV_PR_FMT ", freq: %d, type: %d", NETDEV_PR_ARG,
- __entry->freq, __entry->type)
+ TP_printk(NETDEV_PR_FMT CHAN_DEF_PR_FMT,
+ NETDEV_PR_ARG, CHAN_DEF_PR_ARG)
);

DECLARE_EVENT_CLASS(cfg80211_rx_evt,
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 742ab6e..da3307f 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -784,6 +784,9 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct cfg80211_chan_def chandef = {
+ ._type = NL80211_CHAN_NO_HT,
+ };
int freq, err;

switch (wdev->iftype) {
@@ -797,8 +800,11 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
return freq;
if (freq == 0)
return -EINVAL;
+ chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
+ if (!chandef.chan)
+ return -EINVAL;
mutex_lock(&rdev->devlist_mtx);
- err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
+ err = cfg80211_set_monitor_channel(rdev, &chandef);
mutex_unlock(&rdev->devlist_mtx);
return err;
case NL80211_IFTYPE_MESH_POINT:
@@ -807,9 +813,11 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
return freq;
if (freq == 0)
return -EINVAL;
+ chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
+ if (!chandef.chan)
+ return -EINVAL;
mutex_lock(&rdev->devlist_mtx);
- err = cfg80211_set_mesh_freq(rdev, wdev, freq,
- NL80211_CHAN_NO_HT);
+ err = cfg80211_set_mesh_channel(rdev, wdev, &chandef);
mutex_unlock(&rdev->devlist_mtx);
return err;
default:
@@ -823,8 +831,8 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
- struct ieee80211_channel *chan;
- enum nl80211_channel_type channel_type;
+ struct cfg80211_chan_def chandef;
+ int ret;

switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
@@ -835,10 +843,10 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
if (!rdev->ops->get_channel)
return -EINVAL;

- chan = rdev_get_channel(rdev, wdev, &channel_type);
- if (!chan)
- return -EINVAL;
- freq->m = chan->center_freq;
+ ret = rdev_get_channel(rdev, wdev, &chandef);
+ if (ret)
+ return ret;
+ freq->m = chandef.chan->center_freq;
freq->e = 6;
return 0;
default:
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index 1f773f6..e6e5dbf 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -119,7 +119,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
* channel we disconnected above and reconnect below.
*/
if (chan && !wdev->wext.connect.ssid_len) {
- err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
+ struct cfg80211_chan_def chandef = {
+ ._type = NL80211_CHAN_NO_HT,
+ };
+
+ chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
+ if (chandef.chan)
+ err = cfg80211_set_monitor_channel(rdev, &chandef);
+ else
+ err = -EINVAL;
goto out;
}

--
1.8.0


2012-11-17 23:31:28

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: VHT support, take 2

On Sat, Nov 17, 2012 at 09:48:28AM +0100, Johannes Berg wrote:
> On Fri, 2012-11-16 at 16:10 -0800, Luis R. Rodriguez wrote:
>
> > > >Yeah, actually I'm not sure it's that easy. We'll also need per
> > > >bandwidth TX power restrictions, raise the 40 MHz bandwidth restriction
> > > >to 160 MHz (or get rid of it entirely), etc. That seems to require a new
> > > >regulatory database format?
> > >
> > > Luis discussed the regulatory framework during the wireless summit
> > > in Barcelona last week. My (possibly limited) recollection was that
> > > the current regulatory code can accommodate VHT limits as well. I
> > > assume that also includes the regulatory database format.
> >
> > The only thing mentioned which I had not considered is the per bandwidth
> > TX power restrictions. Where did these come from ?
>
> As usual, they come from the regulations :-)

Which one in particular decided to add per bandwidth
TX power restrictions for VHT ?

Luis

2012-11-09 20:20:59

by Johannes Berg

[permalink] [raw]
Subject: Re: VHT support, take 2

On Fri, 2012-11-09 at 21:17 +0100, Johannes Berg wrote:

> What I intend to do next is this have a patch to parse the VHT
> operation IE in mac80211 (or have a helper in cfg80211?) to
> select the VHT channel configuration in MLME code.
>
> I'm kinda hoping the posedge folks will come back with the
> regulatory code so I don't have to worry about that ...
> *hint hint* :-)
>
> After that, I'll need to work on the remaining hostapd code,
> that should just need channel configuration etc. now. Then I
> think it just needs a good test run.
>
> I'm not interested in VHT IBSS, so I'm not going to do anything
> there, nor VHT mesh.
>
> The other thing would be rate control, e.g. minstrel_vht, but
> I'm not sure we can use minstrel at all, so I'll probalby not
> work on minstrel myself.

Oh and then of course there's also a whole bunch of action frame
handling that will be needed in mac80211, but I'm not really sure yet
what that actually is.

johannes


2012-11-19 04:18:32

by Mahesh Palivela

[permalink] [raw]
Subject: Re: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

On 11/16/2012 06:07 PM, Johannes Berg wrote:
> On Fri, 2012-11-16 at 17:51 +0530, Mahesh Palivela wrote:
>> On 11/10/2012 01:47 AM, Johannes Berg wrote:
>>> From: Johannes Berg <[email protected]>
>>>
>>
>>> + *
>>> + * @NL80211_CHAN_WIDTH_20_NOHT: 20 MHz, non-HT channel
>>
>> Should we have NL80211_CHAN_WIDTH_LEGACY or rename
>> NL80211_CHAN_WIDTH_20_NOHT to NL80211_CHAN_WIDTH_NOHT to cover non HT
>> associations in both 2.4 & 5 GHz bands.
>
> Huh? I must be misunderstanding something -- both 2.4 and 5 GHz bands
> use 20 MHz bandwidth by default?
>

2.4 band channel spacing is 5 MHz and we can use 20 MHz bandwidth only
in HT mode.

2012-11-20 12:56:46

by Mahesh Palivela

[permalink] [raw]
Subject: RE: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

No objections from me Johannes. Please commit.

Thanks,
Mahesh

________________________________________
From: Johannes Berg [[email protected]]
Sent: Tuesday, November 20, 2012 5:51 PM
To: Mahesh Palivela
Cc: [email protected]
Subject: Re: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

On Tue, 2012-11-20 at 17:29 +0530, Mahesh Palivela wrote:

> >>> For loops in both functions seems to be similar. One return false, other
> >>> return -EINVAL. Can we remove duplication?
> >>
> >> True, but they check different flags. I suppose we could have a common
> >> function where the checked flags are passed in, I can try that.
> >
> > I'll add this to the patch:
> >
> > http://p.sipsolutions.net/24eb25fb98ef2d0b.txt
> >
>
> Looks good to me Johannes. Overall your VHT channel config
> implementation done so well.

Thanks for reviewing!

> Partial regulatory check in nl80211_parse_chandef() has to be modified
> to include BW check. I see your TODO comment there.

Yes, although I'm not completely sure the bandwidth check ever made
sense? We'll need to discuss that.

Regardless of that though, I'm tempted to put this into the tree now. As
we don't have any drivers (but hwsim) using it, we won't have any
regulatory issues without the bandwidth check for now, and then we can
base further work on this.

Any objections from you? If not I'll repost the whole thing as [PATCH].

johannes


2012-11-09 20:17:04

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2 5/8] mac80211: convert to channel definition struct

From: Johannes Berg <[email protected]>

Convert mac80211 (and where necessary, some drivers a
little bit) to the new channel definition struct.

This will allow extending mac80211 for VHT, which is
currently restricted to channel contexts since there
are no drivers using that which makes it easier. As
I also don't care about VHT for drivers not using the
channel context API, I won't convert the previous API
to VHT support.

Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 33 +++++----
drivers/net/wireless/ti/wlcore/main.c | 9 +--
include/net/mac80211.h | 17 ++---
net/mac80211/cfg.c | 41 ++++-------
net/mac80211/chan.c | 129 ++++++++++------------------------
net/mac80211/debugfs_netdev.c | 2 -
net/mac80211/ibss.c | 34 ++++-----
net/mac80211/ieee80211_i.h | 18 +++--
net/mac80211/iface.c | 5 +-
net/mac80211/main.c | 21 ++++--
net/mac80211/mesh.c | 28 +++-----
net/mac80211/mesh_plink.c | 19 ++---
net/mac80211/mlme.c | 26 ++++---
net/mac80211/rate.c | 5 +-
net/mac80211/rate.h | 2 +-
net/mac80211/sta_info.c | 2 +-
net/mac80211/sta_info.h | 4 +-
net/mac80211/trace.h | 23 +++---
net/mac80211/tx.c | 20 +++---
net/mac80211/util.c | 45 ++++++------
20 files changed, 221 insertions(+), 262 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 7ef42c6..eb7a1dc 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -681,7 +681,7 @@ static void mac80211_hwsim_tx_iter(void *_data, u8 *addr,
return;

if (!hwsim_chans_compat(data->channel,
- rcu_dereference(vif->chanctx_conf)->channel))
+ rcu_dereference(vif->chanctx_conf)->def.chan))
return;

data->receive = true;
@@ -801,7 +801,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
} else {
chanctx_conf = rcu_dereference(txi->control.vif->chanctx_conf);
if (chanctx_conf)
- channel = chanctx_conf->channel;
+ channel = chanctx_conf->def.chan;
else
channel = NULL;
}
@@ -946,7 +946,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
return;

mac80211_hwsim_tx_frame(hw, skb,
- rcu_dereference(vif->chanctx_conf)->channel);
+ rcu_dereference(vif->chanctx_conf)->def.chan);
}


@@ -1076,9 +1076,8 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
}

if (changed & BSS_CHANGED_HT) {
- wiphy_debug(hw->wiphy, " HT: op_mode=0x%x, chantype=%s\n",
- info->ht_operation_mode,
- hwsim_chantypes[info->channel_type]);
+ wiphy_debug(hw->wiphy, " HT: op_mode=0x%x\n",
+ info->ht_operation_mode);
}

if (changed & BSS_CHANGED_BASIC_RATES) {
@@ -1465,16 +1464,20 @@ static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
hwsim_set_chanctx_magic(ctx);
- wiphy_debug(hw->wiphy, "add channel context %d MHz/%d\n",
- ctx->channel->center_freq, ctx->channel_type);
+ wiphy_debug(hw->wiphy,
+ "add channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n",
+ ctx->def.chan->center_freq, ctx->def.width,
+ ctx->def.center_freq1, ctx->def.center_freq2);
return 0;
}

static void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
- wiphy_debug(hw->wiphy, "remove channel context %d MHz/%d\n",
- ctx->channel->center_freq, ctx->channel_type);
+ wiphy_debug(hw->wiphy,
+ "remove channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n",
+ ctx->def.chan->center_freq, ctx->def.width,
+ ctx->def.center_freq1, ctx->def.center_freq2);
hwsim_check_chanctx_magic(ctx);
hwsim_clear_chanctx_magic(ctx);
}
@@ -1484,8 +1487,10 @@ static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw,
u32 changed)
{
hwsim_check_chanctx_magic(ctx);
- wiphy_debug(hw->wiphy, "change channel context %#x (%d MHz/%d)\n",
- changed, ctx->channel->center_freq, ctx->channel_type);
+ wiphy_debug(hw->wiphy,
+ "change channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n",
+ ctx->def.chan->center_freq, ctx->def.width,
+ ctx->def.center_freq1, ctx->def.center_freq2);
}

static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw,
@@ -1607,7 +1612,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)

rcu_read_lock();
mac80211_hwsim_tx_frame(data->hw, skb,
- rcu_dereference(vif->chanctx_conf)->channel);
+ rcu_dereference(vif->chanctx_conf)->def.chan);
rcu_read_unlock();
}

@@ -1639,7 +1644,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,

rcu_read_lock();
mac80211_hwsim_tx_frame(data->hw, skb,
- rcu_dereference(vif->chanctx_conf)->channel);
+ rcu_dereference(vif->chanctx_conf)->def.chan);
rcu_read_unlock();
}

diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 380cf1f..4f1a05b 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -3791,7 +3791,7 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,

/* Handle HT information change */
if ((changed & BSS_CHANGED_HT) &&
- (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+ (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) {
ret = wl1271_acx_set_ht_information(wl, wlvif,
bss_conf->ht_operation_mode);
if (ret < 0) {
@@ -3905,7 +3905,8 @@ sta_not_found:
u32 rates;
int ieoffset;
wlvif->aid = bss_conf->aid;
- wlvif->channel_type = bss_conf->channel_type;
+ wlvif->channel_type =
+ cfg80211_get_chandef_type(&bss_conf->chandef);
wlvif->beacon_int = bss_conf->beacon_int;
do_join = true;
set_assoc = true;
@@ -4071,7 +4072,7 @@ sta_not_found:
/* Handle new association with HT. Do this after join. */
if (sta_exists) {
if ((changed & BSS_CHANGED_HT) &&
- (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+ (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) {
ret = wl1271_acx_set_ht_capabilities(wl,
&sta_ht_cap,
true,
@@ -4098,7 +4099,7 @@ sta_not_found:

/* Handle HT information change. Done after join. */
if ((changed & BSS_CHANGED_HT) &&
- (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+ (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) {
ret = wl1271_acx_set_ht_information(wl, wlvif,
bss_conf->ht_operation_mode);
if (ret < 0) {
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index bdb8f4f..52807d4 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -145,11 +145,11 @@ struct ieee80211_low_level_stats {

/**
* enum ieee80211_chanctx_change - change flag for channel context
- * @IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE: The channel type was changed
+ * @IEEE80211_CHANCTX_CHANGE_WIDTH: The channel width changed
* @IEEE80211_CHANCTX_CHANGE_RX_CHAINS: The number of RX chains changed
*/
enum ieee80211_chanctx_change {
- IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE = BIT(0),
+ IEEE80211_CHANCTX_CHANGE_WIDTH = BIT(0),
IEEE80211_CHANCTX_CHANGE_RX_CHAINS = BIT(1),
};

@@ -159,8 +159,7 @@ enum ieee80211_chanctx_change {
* This is the driver-visible part. The ieee80211_chanctx
* that contains it is visible in mac80211 only.
*
- * @channel: the channel to tune to
- * @channel_type: the channel (HT) type
+ * @def: the channel definition
* @rx_chains_static: The number of RX chains that must always be
* active on the channel to receive MIMO transmissions
* @rx_chains_dynamic: The number of RX chains that must be enabled
@@ -170,8 +169,7 @@ enum ieee80211_chanctx_change {
* sizeof(void *), size is determined in hw information.
*/
struct ieee80211_chanctx_conf {
- struct ieee80211_channel *channel;
- enum nl80211_channel_type channel_type;
+ struct cfg80211_chan_def def;

u8 rx_chains_static, rx_chains_dynamic;

@@ -288,9 +286,8 @@ enum ieee80211_rssi_event {
* @mcast_rate: per-band multicast rate index + 1 (0: disabled)
* @bssid: The BSSID for this BSS
* @enable_beacon: whether beaconing should be enabled or not
- * @channel_type: Channel type for this BSS -- the hardware might be
- * configured for HT40+ while this BSS only uses no-HT, for
- * example.
+ * @chandef: Channel definition for this BSS -- the hardware might be
+ * configured a higher bandwidth than this BSS uses, for example.
* @ht_operation_mode: HT operation mode like in &struct ieee80211_ht_operation.
* This field is only valid when the channel type is one of the HT types.
* @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
@@ -339,7 +336,7 @@ struct ieee80211_bss_conf {
u16 ht_operation_mode;
s32 cqm_rssi_thold;
u32 cqm_rssi_hyst;
- enum nl80211_channel_type channel_type;
+ struct cfg80211_chan_def chandef;
__be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
u8 arp_addr_cnt;
bool arp_filter_enabled;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index d83bb68..91823ad 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -618,7 +618,7 @@ do_survey:
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (chanctx_conf)
- channel = chanctx_conf->channel;
+ channel = chanctx_conf->def.chan;
else
channel = NULL;
rcu_read_unlock();
@@ -742,13 +742,9 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata;
- enum nl80211_channel_type channel_type;
int ret = 0;

- channel_type = cfg80211_get_chandef_type(chandef);
-
- if (local->monitor_channel == chandef->chan &&
- local->monitor_channel_type == channel_type)
+ if (cfg80211_chandef_identical(&local->monitor_chandef, chandef))
return 0;

mutex_lock(&local->iflist_mtx);
@@ -758,20 +754,17 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
lockdep_is_held(&local->iflist_mtx));
if (sdata) {
ieee80211_vif_release_channel(sdata);
- ret = ieee80211_vif_use_channel(
- sdata, chandef->chan, channel_type,
+ ret = ieee80211_vif_use_channel(sdata, chandef,
IEEE80211_CHANCTX_EXCLUSIVE);
}
} else if (local->open_count == local->monitors) {
local->_oper_channel = chandef->chan;
- local->_oper_channel_type = channel_type;
+ local->_oper_channel_type = cfg80211_get_chandef_type(chandef);
ieee80211_hw_config(local, 0);
}

- if (ret == 0) {
- local->monitor_channel = chandef->chan;
- local->monitor_channel_type = channel_type;
- }
+ if (ret == 0)
+ local->monitor_chandef = *chandef;
mutex_unlock(&local->iflist_mtx);

return ret;
@@ -893,10 +886,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
sdata->smps_mode = IEEE80211_SMPS_OFF;
sdata->needed_rx_chains = sdata->local->rx_chains;

- err = ieee80211_vif_use_channel(
- sdata, params->chandef.chan,
- cfg80211_get_chandef_type(&params->chandef),
- IEEE80211_CHANCTX_SHARED);
+ err = ieee80211_vif_use_channel(sdata, &params->chandef,
+ IEEE80211_CHANCTX_SHARED);
if (err)
return err;

@@ -1737,10 +1728,8 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
sdata->smps_mode = IEEE80211_SMPS_OFF;
sdata->needed_rx_chains = sdata->local->rx_chains;

- err = ieee80211_vif_use_channel(
- sdata, setup->chandef.chan,
- cfg80211_get_chandef_type(&setup->chandef),
- IEEE80211_CHANCTX_SHARED);
+ err = ieee80211_vif_use_channel(sdata, &setup->chandef,
+ IEEE80211_CHANCTX_SHARED);
if (err)
return err;

@@ -2160,7 +2149,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
* the new value until we associate.
*/
if (!sdata->u.mgd.associated ||
- sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
+ sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
return 0;

ap = sdata->u.mgd.associated->bssid;
@@ -2616,7 +2605,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);

if (chanctx_conf)
- need_offchan = chan != chanctx_conf->channel;
+ need_offchan = chan != chanctx_conf->def.chan;
else
need_offchan = true;
rcu_read_unlock();
@@ -3084,7 +3073,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
rcu_read_unlock();
return -EINVAL;
}
- band = chanctx_conf->channel->band;
+ band = chanctx_conf->def.chan->band;
sta = sta_info_get(sdata, peer);
if (sta) {
qos = test_sta_flag(sta, WLAN_STA_WME);
@@ -3152,9 +3141,7 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (chanctx_conf) {
- cfg80211_chandef_create(chandef,
- chanctx_conf->channel,
- chanctx_conf->channel_type);
+ *chandef = chanctx_conf->def;
ret = 0;
}
rcu_read_unlock();
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index a2b06d4..b3f808a 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -8,93 +8,47 @@
#include "ieee80211_i.h"
#include "driver-ops.h"

-static bool
-ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1,
- enum nl80211_channel_type chantype2,
- enum nl80211_channel_type *compat)
+static void ieee80211_change_chandef(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx,
+ const struct cfg80211_chan_def *chandef)
{
- /*
- * start out with chantype1 being the result,
- * overwriting later if needed
- */
- if (compat)
- *compat = chantype1;
-
- switch (chantype1) {
- case NL80211_CHAN_NO_HT:
- if (compat)
- *compat = chantype2;
- break;
- case NL80211_CHAN_HT20:
- /*
- * allow any change that doesn't go to no-HT
- * (if it already is no-HT no change is needed)
- */
- if (chantype2 == NL80211_CHAN_NO_HT)
- break;
- if (compat)
- *compat = chantype2;
- break;
- case NL80211_CHAN_HT40PLUS:
- case NL80211_CHAN_HT40MINUS:
- /* allow smaller bandwidth and same */
- if (chantype2 == NL80211_CHAN_NO_HT)
- break;
- if (chantype2 == NL80211_CHAN_HT20)
- break;
- if (chantype2 == chantype1)
- break;
- return false;
- }
-
- return true;
-}
-
-static void ieee80211_change_chantype(struct ieee80211_local *local,
- struct ieee80211_chanctx *ctx,
- enum nl80211_channel_type chantype)
-{
- if (chantype == ctx->conf.channel_type)
+ if (cfg80211_chandef_identical(&ctx->conf.def, chandef))
return;

- ctx->conf.channel_type = chantype;
- drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE);
+ WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef));
+
+ ctx->conf.def = *chandef;
+ drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH);

if (!local->use_chanctx) {
- local->_oper_channel_type = chantype;
+ local->_oper_channel_type = cfg80211_get_chandef_type(chandef);
ieee80211_hw_config(local, 0);
}
}

static struct ieee80211_chanctx *
ieee80211_find_chanctx(struct ieee80211_local *local,
- struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type,
+ const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode)
{
struct ieee80211_chanctx *ctx;
- enum nl80211_channel_type compat_type;

lockdep_assert_held(&local->chanctx_mtx);

if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
return NULL;
- if (WARN_ON(!channel))
- return NULL;

list_for_each_entry(ctx, &local->chanctx_list, list) {
- compat_type = ctx->conf.channel_type;
+ const struct cfg80211_chan_def *compat;

if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
continue;
- if (ctx->conf.channel != channel)
- continue;
- if (!ieee80211_channel_types_are_compatible(ctx->conf.channel_type,
- channel_type,
- &compat_type))
+
+ compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef);
+ if (!compat)
continue;

- ieee80211_change_chantype(local, ctx, compat_type);
+ ieee80211_change_chandef(local, ctx, compat);

return ctx;
}
@@ -104,8 +58,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local,

static struct ieee80211_chanctx *
ieee80211_new_chanctx(struct ieee80211_local *local,
- struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type,
+ const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode)
{
struct ieee80211_chanctx *ctx;
@@ -117,15 +70,15 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
if (!ctx)
return ERR_PTR(-ENOMEM);

- ctx->conf.channel = channel;
- ctx->conf.channel_type = channel_type;
+ ctx->conf.def = *chandef;
ctx->conf.rx_chains_static = 1;
ctx->conf.rx_chains_dynamic = 1;
ctx->mode = mode;

if (!local->use_chanctx) {
- local->_oper_channel_type = channel_type;
- local->_oper_channel = channel;
+ local->_oper_channel_type =
+ cfg80211_get_chandef_type(chandef);
+ local->_oper_channel = chandef->chan;
ieee80211_hw_config(local, 0);
} else {
err = drv_add_chanctx(local, ctx);
@@ -178,41 +131,38 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
return 0;
}

-static enum nl80211_channel_type
-ieee80211_calc_chantype(struct ieee80211_local *local,
- struct ieee80211_chanctx *ctx)
+static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx)
{
struct ieee80211_chanctx_conf *conf = &ctx->conf;
struct ieee80211_sub_if_data *sdata;
- enum nl80211_channel_type result = NL80211_CHAN_NO_HT;
+ const struct cfg80211_chan_def *compat = NULL;

lockdep_assert_held(&local->chanctx_mtx);

rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+
if (!ieee80211_sdata_running(sdata))
continue;
if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
continue;

- WARN_ON_ONCE(!ieee80211_channel_types_are_compatible(
- sdata->vif.bss_conf.channel_type,
- result, &result));
+ if (!compat)
+ compat = &sdata->vif.bss_conf.chandef;
+
+ compat = cfg80211_chandef_compatible(
+ &sdata->vif.bss_conf.chandef, compat);
+ if (!compat)
+ break;
+
}
rcu_read_unlock();

- return result;
-}
-
-static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
- struct ieee80211_chanctx *ctx)
-{
- enum nl80211_channel_type chantype;
-
- lockdep_assert_held(&local->chanctx_mtx);
+ if (WARN_ON_ONCE(!compat))
+ return;

- chantype = ieee80211_calc_chantype(local, ctx);
- ieee80211_change_chantype(local, ctx, chantype);
+ ieee80211_change_chandef(local, ctx, compat);
}

static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
@@ -337,8 +287,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
}

int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type,
+ const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode)
{
struct ieee80211_local *local = sdata->local;
@@ -350,15 +299,15 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
mutex_lock(&local->chanctx_mtx);
__ieee80211_vif_release_channel(sdata);

- ctx = ieee80211_find_chanctx(local, channel, channel_type, mode);
+ ctx = ieee80211_find_chanctx(local, chandef, mode);
if (!ctx)
- ctx = ieee80211_new_chanctx(local, channel, channel_type, mode);
+ ctx = ieee80211_new_chanctx(local, chandef, mode);
if (IS_ERR(ctx)) {
ret = PTR_ERR(ctx);
goto out;
}

- sdata->vif.bss_conf.channel_type = channel_type;
+ sdata->vif.bss_conf.chandef = *chandef;

ret = ieee80211_assign_vif_chanctx(sdata, ctx);
if (ret) {
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index ba9bd0e..cbde5cc 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -168,7 +168,6 @@ IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz,

IEEE80211_IF_FILE(flags, flags, HEX);
IEEE80211_IF_FILE(state, state, LHEX);
-IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC);
IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC);
IEEE80211_IF_FILE(ap_power_level, ap_power_level, DEC);
IEEE80211_IF_FILE(user_power_level, user_power_level, DEC);
@@ -632,7 +631,6 @@ static void add_files(struct ieee80211_sub_if_data *sdata)

DEBUGFS_ADD(flags);
DEBUGFS_ADD(state);
- DEBUGFS_ADD(channel_type);
DEBUGFS_ADD(txpower);
DEBUGFS_ADD(user_power_level);
DEBUGFS_ADD(ap_power_level);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index c427cf3..e9e29ad 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -52,7 +52,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
u32 bss_change;
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
struct cfg80211_chan_def chandef;
- enum nl80211_channel_type chan_type;

lockdep_assert_held(&ifibss->mtx);

@@ -80,13 +79,14 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,

sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;

- chan_type = ifibss->channel_type;
- cfg80211_chandef_create(&chandef, chan, chan_type);
- if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef))
- chan_type = NL80211_CHAN_HT20;
+ cfg80211_chandef_create(&chandef, chan, ifibss->channel_type);
+ if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
+ chandef.width = NL80211_CHAN_WIDTH_20;
+ chandef.center_freq1 = chan->center_freq;
+ }

ieee80211_vif_release_channel(sdata);
- if (ieee80211_vif_use_channel(sdata, chan, chan_type,
+ if (ieee80211_vif_use_channel(sdata, &chandef,
ifibss->fixed_channel ?
IEEE80211_CHANCTX_SHARED :
IEEE80211_CHANCTX_EXCLUSIVE)) {
@@ -160,7 +160,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
ifibss->ie, ifibss->ie_len);

/* add HT capability and information IEs */
- if (chan_type != NL80211_CHAN_NO_HT &&
+ if (chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
sband->ht_cap.ht_supported) {
pos = skb_put(skb, 4 +
sizeof(struct ieee80211_ht_cap) +
@@ -173,7 +173,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
* keep them at 0
*/
pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
- chan, chan_type, 0);
+ &chandef, 0);
}

if (local->hw.queues >= IEEE80211_NUM_ACS) {
@@ -329,7 +329,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON_ONCE(!chanctx_conf))
return NULL;
- band = chanctx_conf->channel->band;
+ band = chanctx_conf->def.chan->band;
rcu_read_unlock();

sta = sta_info_alloc(sdata, addr, GFP_KERNEL);
@@ -476,9 +476,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) {
/* we both use HT */
struct ieee80211_sta_ht_cap sta_ht_cap_new;
- enum nl80211_channel_type channel_type =
- ieee80211_ht_oper_to_channel_type(
- elems->ht_operation);
+ struct cfg80211_chan_def chandef;
+
+ ieee80211_ht_oper_to_chandef(channel,
+ elems->ht_operation,
+ &chandef);

ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
elems->ht_cap_elem,
@@ -488,9 +490,9 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
* fall back to HT20 if we don't use or use
* the other extension channel
*/
- if (!(channel_type == NL80211_CHAN_HT40MINUS ||
- channel_type == NL80211_CHAN_HT40PLUS) ||
- channel_type != sdata->u.ibss.channel_type)
+ if (chandef.width != NL80211_CHAN_WIDTH_40 ||
+ cfg80211_get_chandef_type(&chandef) !=
+ sdata->u.ibss.channel_type)
sta_ht_cap_new.cap &=
~IEEE80211_HT_CAP_SUP_WIDTH_20_40;

@@ -633,7 +635,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();
return;
}
- band = chanctx_conf->channel->band;
+ band = chanctx_conf->def.chan->band;
rcu_read_unlock();

sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 6f747cf..666e9d9 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -799,7 +799,7 @@ ieee80211_get_sdata_band(struct ieee80211_sub_if_data *sdata)
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!WARN_ON(!chanctx_conf))
- band = chanctx_conf->channel->band;
+ band = chanctx_conf->def.chan->band;
rcu_read_unlock();

return band;
@@ -1156,8 +1156,7 @@ struct ieee80211_local {

/* virtual monitor interface */
struct ieee80211_sub_if_data __rcu *monitor_sdata;
- struct ieee80211_channel *monitor_channel;
- enum nl80211_channel_type monitor_channel_type;
+ struct cfg80211_chan_def monitor_chandef;
};

static inline struct ieee80211_sub_if_data *
@@ -1500,7 +1499,7 @@ static inline void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
}

__ieee80211_tx_skb_tid_band(sdata, skb, tid,
- chanctx_conf->channel->band);
+ chanctx_conf->def.chan->band);
rcu_read_unlock();
}

@@ -1589,8 +1588,7 @@ size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
u16 cap);
u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
- struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type,
+ const struct cfg80211_chan_def *chandef,
u16 prot_mode);
u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
u32 cap);
@@ -1602,13 +1600,13 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
enum ieee80211_band band);

/* channel management */
-enum nl80211_channel_type
-ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper);
+void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
+ struct ieee80211_ht_operation *ht_oper,
+ struct cfg80211_chan_def *chandef);

int __must_check
ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type,
+ const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode);
void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);

diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 80ce90b..5331662 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -54,7 +54,7 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
return false;
}

- power = chanctx_conf->channel->max_power;
+ power = chanctx_conf->def.chan->max_power;
rcu_read_unlock();

if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL)
@@ -415,8 +415,7 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
goto out_unlock;
}

- ret = ieee80211_vif_use_channel(sdata, local->monitor_channel,
- local->monitor_channel_type,
+ ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef,
IEEE80211_CHANCTX_EXCLUSIVE);
if (ret) {
drv_remove_interface(local, sdata);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index cd88a4b..05135c6 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -799,10 +799,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
local->_oper_channel = &sband->channels[0];
local->hw.conf.channel_type = NL80211_CHAN_NO_HT;
}
- if (!local->monitor_channel) {
- local->monitor_channel = &sband->channels[0];
- local->monitor_channel_type = NL80211_CHAN_NO_HT;
- }
+ cfg80211_chandef_create(&local->monitor_chandef,
+ &sband->channels[0],
+ NL80211_CHAN_NO_HT);
channels += sband->n_channels;

if (max_bitrates < sband->n_bitrates)
@@ -885,10 +884,22 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (supp_ht)
local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap);

- if (supp_vht)
+ if (supp_vht) {
local->scan_ies_len +=
2 + sizeof(struct ieee80211_vht_cap);

+ /*
+ * (for now at least), drivers wanting to use VHT must
+ * support channel contexts, as they contain all the
+ * necessary VHT information and the global hw config
+ * doesn't (yet)
+ */
+ if (WARN_ON(!local->use_chanctx)) {
+ result = -EINVAL;
+ goto fail_wiphy_register;
+ }
+ }
+
if (!local->ops->hw_scan) {
/* For hw_scan, driver needs to set these up. */
local->hw.wiphy->max_scan_ssids = 4;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index a350cab..50a3b47 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -76,7 +76,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_local *local = sdata->local;
u32 basic_rates = 0;
- enum nl80211_channel_type sta_channel_type = NL80211_CHAN_NO_HT;
+ struct cfg80211_chan_def sta_chan_def;

/*
* As support for each feature is added, check for matching
@@ -103,17 +103,11 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
if (sdata->vif.bss_conf.basic_rates != basic_rates)
goto mismatch;

- if (ie->ht_operation)
- sta_channel_type =
- ieee80211_ht_oper_to_channel_type(ie->ht_operation);
-
- /* Disallow HT40+/- mismatch */
- if (ie->ht_operation &&
- (sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40MINUS ||
- sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40PLUS) &&
- (sta_channel_type == NL80211_CHAN_HT40MINUS ||
- sta_channel_type == NL80211_CHAN_HT40PLUS) &&
- sdata->vif.bss_conf.channel_type != sta_channel_type)
+ ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
+ ie->ht_operation, &sta_chan_def);
+
+ if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
+ &sta_chan_def))
goto mismatch;

return true;
@@ -368,7 +362,7 @@ int mesh_add_ds_params_ie(struct sk_buff *skb,
rcu_read_unlock();
return -EINVAL;
}
- chan = chanctx_conf->channel;
+ chan = chanctx_conf->def.chan;
rcu_read_unlock();

sband = local->hw.wiphy->bands[chan->band];
@@ -392,7 +386,7 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb,

sband = local->hw.wiphy->bands[band];
if (!sband->ht_cap.ht_supported ||
- sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
+ sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
return 0;

if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap))
@@ -411,7 +405,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb,
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *channel;
enum nl80211_channel_type channel_type =
- sdata->vif.bss_conf.channel_type;
+ cfg80211_get_chandef_type(&sdata->vif.bss_conf.chandef);
struct ieee80211_supported_band *sband;
struct ieee80211_sta_ht_cap *ht_cap;
u8 *pos;
@@ -422,7 +416,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb,
rcu_read_unlock();
return -EINVAL;
}
- channel = chanctx_conf->channel;
+ channel = chanctx_conf->def.chan;
rcu_read_unlock();

sband = local->hw.wiphy->bands[channel->band];
@@ -435,7 +429,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb,
return -ENOMEM;

pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
- ieee80211_ie_build_ht_oper(pos, ht_cap, channel, channel_type,
+ ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef,
sdata->vif.bss_conf.ht_operation_mode);

return 0;
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 234fe75..676c20d 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -117,7 +117,7 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
u16 ht_opmode;
bool non_ht_sta = false, ht20_sta = false;

- if (sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
+ if (sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
return 0;

rcu_read_lock();
@@ -126,14 +126,14 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
sta->plink_state != NL80211_PLINK_ESTAB)
continue;

- switch (sta->ch_type) {
- case NL80211_CHAN_NO_HT:
+ switch (sta->ch_width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
mpl_dbg(sdata,
"mesh_plink %pM: nonHT sta (%pM) is present\n",
sdata->vif.addr, sta->sta.addr);
non_ht_sta = true;
goto out;
- case NL80211_CHAN_HT20:
+ case NL80211_CHAN_WIDTH_20:
mpl_dbg(sdata,
"mesh_plink %pM: HT20 sta (%pM) is present\n",
sdata->vif.addr, sta->sta.addr);
@@ -148,7 +148,7 @@ out:
if (non_ht_sta)
ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED;
else if (ht20_sta &&
- sdata->vif.bss_conf.channel_type > NL80211_CHAN_HT20)
+ sdata->vif.bss_conf.chandef.width > NL80211_CHAN_WIDTH_20)
ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ;
else
ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
@@ -378,7 +378,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,

sta->sta.supp_rates[band] = rates;
if (elems->ht_cap_elem &&
- sdata->vif.bss_conf.channel_type != NL80211_CHAN_NO_HT)
+ sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
elems->ht_cap_elem,
&sta->sta.ht_cap);
@@ -386,12 +386,15 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap));

if (elems->ht_operation) {
+ struct cfg80211_chan_def chandef;
+
if (!(elems->ht_operation->ht_param &
IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
sta->sta.ht_cap.cap &=
~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- sta->ch_type =
- ieee80211_ht_oper_to_channel_type(elems->ht_operation);
+ ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
+ elems->ht_operation, &chandef);
+ sta->ch_width = chandef.width;
}

rate_control_rate_init(sta);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 856e562..29516dd 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -191,17 +191,19 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();
return 0;
}
- chan = chanctx_conf->channel;
+ chan = chanctx_conf->def.chan;
rcu_read_unlock();
sband = local->hw.wiphy->bands[chan->band];

- switch (sdata->vif.bss_conf.channel_type) {
- case NL80211_CHAN_HT40PLUS:
- if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
+ switch (sdata->vif.bss_conf.chandef.width) {
+ case NL80211_CHAN_WIDTH_40:
+ if (sdata->vif.bss_conf.chandef.chan->center_freq >
+ sdata->vif.bss_conf.chandef.center_freq1 &&
+ chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
disable_40 = true;
- break;
- case NL80211_CHAN_HT40MINUS:
- if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
+ if (sdata->vif.bss_conf.chandef.chan->center_freq <
+ sdata->vif.bss_conf.chandef.center_freq1 &&
+ chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
disable_40 = true;
break;
default:
@@ -381,7 +383,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
rcu_read_unlock();
return;
}
- chan = chanctx_conf->channel;
+ chan = chanctx_conf->def.chan;
rcu_read_unlock();
sband = local->hw.wiphy->bands[chan->band];

@@ -2496,11 +2498,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
return;
}

- if (rx_status->freq != chanctx_conf->channel->center_freq) {
+ if (rx_status->freq != chanctx_conf->def.chan->center_freq) {
rcu_read_unlock();
return;
}
- chan = chanctx_conf->channel;
+ chan = chanctx_conf->def.chan;
rcu_read_unlock();

if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon &&
@@ -3214,6 +3216,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
const u8 *ht_oper_ie;
const struct ieee80211_ht_operation *ht_oper = NULL;
struct ieee80211_supported_band *sband;
+ struct cfg80211_chan_def chandef;

sband = local->hw.wiphy->bands[cbss->channel->band];

@@ -3294,7 +3297,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
sdata->smps_mode = IEEE80211_SMPS_OFF;

ieee80211_vif_release_channel(sdata);
- return ieee80211_vif_use_channel(sdata, cbss->channel, channel_type,
+ cfg80211_chandef_create(&chandef, cbss->channel, channel_type);
+ return ieee80211_vif_use_channel(sdata, &chandef,
IEEE80211_CHANCTX_SHARED);
}

diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 3313c11..dd88381 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -391,7 +391,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
return;

/* if HT BSS, and we handle a data frame, also try HT rates */
- if (txrc->bss_conf->channel_type == NL80211_CHAN_NO_HT)
+ if (txrc->bss_conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
return;

fc = hdr->frame_control;
@@ -408,8 +408,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,

alt_rate.flags |= IEEE80211_TX_RC_MCS;

- if ((txrc->bss_conf->channel_type == NL80211_CHAN_HT40MINUS) ||
- (txrc->bss_conf->channel_type == NL80211_CHAN_HT40PLUS))
+ if (txrc->bss_conf->chandef.width == NL80211_CHAN_WIDTH_40)
alt_rate.flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;

if (rate_idx_match_mcs_mask(&alt_rate, mcs_mask)) {
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index ec198ef..301386d 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -65,7 +65,7 @@ static inline void rate_control_rate_init(struct sta_info *sta)
return;
}

- sband = local->hw.wiphy->bands[chanctx_conf->channel->band];
+ sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];
rcu_read_unlock();

ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index f7bb54f..0b4a77f 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1087,7 +1087,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
return;
}

- ieee80211_xmit(sdata, skb, chanctx_conf->channel->band);
+ ieee80211_xmit(sdata, skb, chanctx_conf->def.chan->band);
rcu_read_unlock();
}

diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index c88f161f..e0191f0 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -273,7 +273,7 @@ struct sta_ampdu_mlme {
* @t_offset: timing offset relative to this host
* @t_offset_setpoint: reference timing offset of this sta to be used when
* calculating clockdrift
- * @ch_type: peer's channel type
+ * @ch_width: peer's channel width
* @debugfs: debug filesystem info
* @dead: set to true when sta is unlinked
* @uploaded: set to true when sta is uploaded to the driver
@@ -369,7 +369,7 @@ struct sta_info {
struct timer_list plink_timer;
s64 t_offset;
s64 t_offset_setpoint;
- enum nl80211_channel_type ch_type;
+ enum nl80211_chan_width ch_width;
#endif

#ifdef CONFIG_MAC80211_DEBUGFS
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 1b86d60..93cabc8 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -28,16 +28,21 @@
#define VIF_PR_FMT " vif:%s(%d%s)"
#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""

-#define CHANCTX_ENTRY __field(int, freq) \
- __field(int, chantype) \
+#define CHANCTX_ENTRY __field(u32, control_freq) \
+ __field(u32, chan_width) \
+ __field(u32, center_freq1) \
+ __field(u32, center_freq2) \
__field(u8, rx_chains_static) \
__field(u8, rx_chains_dynamic)
-#define CHANCTX_ASSIGN __entry->freq = ctx->conf.channel->center_freq; \
- __entry->chantype = ctx->conf.channel_type; \
+#define CHANCTX_ASSIGN __entry->control_freq = ctx->conf.def.chan->center_freq;\
+ __entry->chan_width = ctx->conf.def.width; \
+ __entry->center_freq1 = ctx->conf.def.center_freq1; \
+ __entry->center_freq2 = ctx->conf.def.center_freq2; \
__entry->rx_chains_static = ctx->conf.rx_chains_static; \
__entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic
-#define CHANCTX_PR_FMT " freq:%d MHz chantype:%d chains:%d/%d"
-#define CHANCTX_PR_ARG __entry->freq, __entry->chantype, \
+#define CHANCTX_PR_FMT " control:%d MHz width:%d center: %d/%d MHz chains:%d/%d"
+#define CHANCTX_PR_ARG __entry->control_freq, __entry->chan_width, \
+ __entry->center_freq1, __entry->center_freq2, \
__entry->rx_chains_static, __entry->rx_chains_dynamic


@@ -334,7 +339,8 @@ TRACE_EVENT(drv_bss_info_changed,
__field(u16, ht_operation_mode)
__field(s32, cqm_rssi_thold);
__field(s32, cqm_rssi_hyst);
- __field(u32, channel_type);
+ __field(u32, channel_width);
+ __field(u32, channel_cfreq1);
__dynamic_array(u32, arp_addr_list, info->arp_addr_cnt);
__field(bool, arp_filter_enabled);
__field(bool, qos);
@@ -370,7 +376,8 @@ TRACE_EVENT(drv_bss_info_changed,
__entry->ht_operation_mode = info->ht_operation_mode;
__entry->cqm_rssi_thold = info->cqm_rssi_thold;
__entry->cqm_rssi_hyst = info->cqm_rssi_hyst;
- __entry->channel_type = info->channel_type;
+ __entry->channel_width = info->chandef.width;
+ __entry->channel_cfreq1 = info->chandef.center_freq1;
memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list,
sizeof(u32) * info->arp_addr_cnt);
__entry->arp_filter_enabled = info->arp_filter_enabled;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index b546887..d8ef341 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1676,7 +1676,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
if (!chanctx_conf)
goto fail_rcu;

- chan = chanctx_conf->channel;
+ chan = chanctx_conf->def.chan;

/*
* Frame injection is not allowed if beaconing is not allowed
@@ -1779,7 +1779,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf);
if (!chanctx_conf)
goto fail_rcu;
- band = chanctx_conf->channel->band;
+ band = chanctx_conf->def.chan->band;
if (sta)
break;
/* fall through */
@@ -1794,7 +1794,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf)
goto fail_rcu;
- band = chanctx_conf->channel->band;
+ band = chanctx_conf->def.chan->band;
break;
case NL80211_IFTYPE_WDS:
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
@@ -1871,7 +1871,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf)
goto fail_rcu;
- band = chanctx_conf->channel->band;
+ band = chanctx_conf->def.chan->band;
break;
#endif
case NL80211_IFTYPE_STATION:
@@ -1930,7 +1930,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf)
goto fail_rcu;
- band = chanctx_conf->channel->band;
+ band = chanctx_conf->def.chan->band;
break;
case NL80211_IFTYPE_ADHOC:
/* DA SA BSSID */
@@ -1941,7 +1941,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf)
goto fail_rcu;
- band = chanctx_conf->channel->band;
+ band = chanctx_conf->def.chan->band;
break;
default:
goto fail_rcu;
@@ -2191,7 +2191,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
return true;
}
result = ieee80211_tx(sdata, skb, true,
- chanctx_conf->channel->band);
+ chanctx_conf->def.chan->band);
} else {
struct sk_buff_head skbs;

@@ -2455,7 +2455,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
*pos++ = WLAN_EID_SSID;
*pos++ = 0x0;

- band = chanctx_conf->channel->band;
+ band = chanctx_conf->def.chan->band;

if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
mesh_add_ds_params_ie(skb, sdata) ||
@@ -2474,7 +2474,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
goto out;
}

- band = chanctx_conf->channel->band;
+ band = chanctx_conf->def.chan->band;

info = IEEE80211_SKB_CB(skb);

@@ -2754,7 +2754,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
info = IEEE80211_SKB_CB(skb);

tx.flags |= IEEE80211_TX_PS_BUFFERED;
- info->band = chanctx_conf->channel->band;
+ info->band = chanctx_conf->def.chan->band;

if (invoke_tx_handlers(&tx))
skb = NULL;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index af38c6f..6b3af01 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -905,7 +905,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
use_11b = (chanctx_conf &&
- chanctx_conf->channel->band == IEEE80211_BAND_2GHZ) &&
+ chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ) &&
!(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
rcu_read_unlock();

@@ -998,7 +998,7 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);

if (chanctx_conf &&
- chanctx_conf->channel->band == IEEE80211_BAND_2GHZ &&
+ chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ &&
have_higher_than_11mbit)
sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
else
@@ -1861,8 +1861,7 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
}

u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
- struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type,
+ const struct cfg80211_chan_def *chandef,
u16 prot_mode)
{
struct ieee80211_ht_operation *ht_oper;
@@ -1870,23 +1869,25 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
*pos++ = WLAN_EID_HT_OPERATION;
*pos++ = sizeof(struct ieee80211_ht_operation);
ht_oper = (struct ieee80211_ht_operation *)pos;
- ht_oper->primary_chan =
- ieee80211_frequency_to_channel(channel->center_freq);
- switch (channel_type) {
- case NL80211_CHAN_HT40MINUS:
- ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
- break;
- case NL80211_CHAN_HT40PLUS:
- ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ ht_oper->primary_chan = ieee80211_frequency_to_channel(
+ chandef->chan->center_freq);
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_160:
+ case NL80211_CHAN_WIDTH_80P80:
+ case NL80211_CHAN_WIDTH_80:
+ case NL80211_CHAN_WIDTH_40:
+ if (chandef->center_freq1 > chandef->chan->center_freq)
+ ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ else
+ ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
break;
- case NL80211_CHAN_HT20:
default:
ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
break;
}
if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
- channel_type != NL80211_CHAN_NO_HT &&
- channel_type != NL80211_CHAN_HT20)
+ chandef->width != NL80211_CHAN_WIDTH_20_NOHT &&
+ chandef->width != NL80211_CHAN_WIDTH_20)
ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;

ht_oper->operation_mode = cpu_to_le16(prot_mode);
@@ -1900,13 +1901,17 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
return pos + sizeof(struct ieee80211_ht_operation);
}

-enum nl80211_channel_type
-ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper)
+void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
+ struct ieee80211_ht_operation *ht_oper,
+ struct cfg80211_chan_def *chandef)
{
enum nl80211_channel_type channel_type;

- if (!ht_oper)
- return NL80211_CHAN_NO_HT;
+ if (!ht_oper) {
+ cfg80211_chandef_create(chandef, control_chan,
+ NL80211_CHAN_NO_HT);
+ return;
+ }

switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
case IEEE80211_HT_PARAM_CHA_SEC_NONE:
@@ -1922,7 +1927,7 @@ ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper)
channel_type = NL80211_CHAN_NO_HT;
}

- return channel_type;
+ cfg80211_chandef_create(chandef, control_chan, channel_type);
}

int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
--
1.8.0


2012-11-09 20:17:05

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2 7/8] mac80211: support drivers reporting VHT RX

From: Johannes Berg <[email protected]>

Add support to mac80211 for having drivers report
received VHT MCS information.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/mac80211.h | 12 +++++++++++-
net/mac80211/cfg.c | 26 +++++++++++++++++++++++---
net/mac80211/ibss.c | 2 +-
net/mac80211/mesh_sync.c | 2 +-
net/mac80211/rx.c | 20 +++++++++++++++-----
net/mac80211/sta_info.h | 4 +++-
6 files changed, 54 insertions(+), 12 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 52807d4..da9fcd6 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -714,7 +714,11 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
* merging.
* @RX_FLAG_SHORTPRE: Short preamble was used for this frame
* @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index
+ * @RX_FLAG_VHT: VHT MCS was used and rate_index is MCS index
* @RX_FLAG_40MHZ: HT40 (40 MHz) was used
+ * @RX_FLAG_80MHZ: 80 MHz was used
+ * @RX_FLAG_80P80MHZ: 80+80 MHz was used
+ * @RX_FLAG_160MHZ: 160 MHz was used
* @RX_FLAG_SHORT_GI: Short guard interval was used
* @RX_FLAG_NO_SIGNAL_VAL: The signal strength value is not present.
* Valid only for data frames (mainly A-MPDU)
@@ -756,6 +760,10 @@ enum mac80211_rx_flags {
RX_FLAG_AMPDU_IS_LAST = BIT(18),
RX_FLAG_AMPDU_DELIM_CRC_ERROR = BIT(19),
RX_FLAG_AMPDU_DELIM_CRC_KNOWN = BIT(20),
+ RX_FLAG_VHT = BIT(21),
+ RX_FLAG_80MHZ = BIT(22),
+ RX_FLAG_80P80MHZ = BIT(23),
+ RX_FLAG_160MHZ = BIT(24),
};

/**
@@ -776,7 +784,8 @@ enum mac80211_rx_flags {
* @IEEE80211_HW_SIGNAL_*
* @antenna: antenna used
* @rate_idx: index of data rate into band's supported rates or MCS index if
- * HT rates are use (RX_FLAG_HT)
+ * HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT)
+ * @vht_nss: number of streams (VHT only)
* @flag: %RX_FLAG_*
* @rx_flags: internal RX flags for mac80211
* @ampdu_reference: A-MPDU reference number, must be a different value for
@@ -790,6 +799,7 @@ struct ieee80211_rx_status {
u32 flag;
u16 freq;
u8 rate_idx;
+ u8 vht_nss;
u8 rx_flags;
u8 band;
u8 antenna;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 91823ad..5e9fdce 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -374,7 +374,8 @@ static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, in
{
enum ieee80211_band band = ieee80211_get_sdata_band(sta->sdata);

- if (!(rate->flags & RATE_INFO_FLAGS_MCS)) {
+ if (!(rate->flags & RATE_INFO_FLAGS_MCS) &&
+ !(rate->flags & RATE_INFO_FLAGS_VHT_MCS)) {
struct ieee80211_supported_band *sband;
sband = sta->local->hw.wiphy->bands[band];
rate->legacy = sband->bitrates[idx].bitrate;
@@ -444,13 +445,32 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);

sinfo->rxrate.flags = 0;
- if (sta->last_rx_rate_flag & RX_FLAG_HT)
+ if (sta->last_rx_rate_flag & RX_FLAG_HT) {
sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS;
+ sinfo->rxrate.mcs = sta->last_rx_rate_idx;
+ } else if (sta->last_rx_rate_flag & RX_FLAG_VHT) {
+ sinfo->rxrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
+ sinfo->rxrate.nss = sta->last_rx_rate_vht_nss;
+ sinfo->rxrate.mcs = sta->last_rx_rate_idx;
+ } else {
+ struct ieee80211_supported_band *sband;
+
+ sband = sta->local->hw.wiphy->bands[
+ ieee80211_get_sdata_band(sta->sdata)];
+ sinfo->rxrate.legacy =
+ sband->bitrates[sta->last_rx_rate_idx].bitrate;
+ }
+
if (sta->last_rx_rate_flag & RX_FLAG_40MHZ)
sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI)
sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
- rate_idx_to_bitrate(&sinfo->rxrate, sta, sta->last_rx_rate_idx);
+ if (sta->last_rx_rate_flag & RX_FLAG_80MHZ)
+ sinfo->rxrate.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
+ if (sta->last_rx_rate_flag & RX_FLAG_80P80MHZ)
+ sinfo->rxrate.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH;
+ if (sta->last_rx_rate_flag & RX_FLAG_160MHZ)
+ sinfo->rxrate.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;

if (ieee80211_vif_is_mesh(&sdata->vif)) {
#ifdef CONFIG_MAC80211_MESH
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index e9e29ad..5e69188 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -565,7 +565,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
*/
int rate;

- if (rx_status->flag & RX_FLAG_HT)
+ if (rx_status->flag & (RX_FLAG_HT | RX_FLAG_VHT))
rate = 65; /* TODO: HT rates */
else
rate = local->hw.wiphy->bands[band]->
diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c
index 407c870..ed2503f 100644
--- a/net/mac80211/mesh_sync.c
+++ b/net/mac80211/mesh_sync.c
@@ -137,7 +137,7 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
*/
int rate;

- if (rx_status->flag & RX_FLAG_HT) {
+ if (rx_status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) {
/* TODO:
* In principle there could be HT-beacons (Dual Beacon
* HT Operation options), but for now ignore them and
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 6ad3303..c45c9ff 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -150,7 +150,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
pos++;

/* IEEE80211_RADIOTAP_RATE */
- if (!rate || status->flag & RX_FLAG_HT) {
+ if (!rate || status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) {
/*
* Without rate information don't add it. If we have,
* MCS information is a separate field in radiotap,
@@ -170,7 +170,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
if (status->band == IEEE80211_BAND_5GHZ)
put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
pos);
- else if (status->flag & RX_FLAG_HT)
+ else if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT))
put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ,
pos);
else if (rate && rate->flags & IEEE80211_RATE_ERP_G)
@@ -1294,6 +1294,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
if (ieee80211_is_data(hdr->frame_control)) {
sta->last_rx_rate_idx = status->rate_idx;
sta->last_rx_rate_flag = status->flag;
+ sta->last_rx_rate_vht_nss = status->vht_nss;
}
}
} else if (!is_multicast_ether_addr(hdr->addr1)) {
@@ -1305,6 +1306,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
if (ieee80211_is_data(hdr->frame_control)) {
sta->last_rx_rate_idx = status->rate_idx;
sta->last_rx_rate_flag = status->flag;
+ sta->last_rx_rate_vht_nss = status->vht_nss;
}
}

@@ -2648,7 +2650,8 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
status = IEEE80211_SKB_RXCB((rx->skb));

sband = rx->local->hw.wiphy->bands[status->band];
- if (!(status->flag & RX_FLAG_HT))
+ if (!(status->flag & RX_FLAG_HT) &&
+ !(status->flag & RX_FLAG_VHT))
rate = &sband->bitrates[status->rate_idx];

ieee80211_rx_cooked_monitor(rx, rate);
@@ -2815,8 +2818,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
} else if (!rx->sta) {
int rate_idx;
- if (status->flag & RX_FLAG_HT)
- rate_idx = 0; /* TODO: HT rates */
+ if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT))
+ rate_idx = 0; /* TODO: HT/VHT rates */
else
rate_idx = status->rate_idx;
ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2,
@@ -3092,6 +3095,13 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
status->rate_idx,
status->rate_idx))
goto drop;
+ } else if (status->flag & RX_FLAG_VHT) {
+ if (WARN_ONCE(status->rate_idx > 9 ||
+ !status->vht_nss ||
+ status->vht_nss > 8,
+ "Rate marked as a VHT rate but data is invalid: MCS: %d, NSS: %d\n",
+ status->rate_idx, status->vht_nss))
+ goto drop;
} else {
if (WARN_ON(status->rate_idx >= sband->n_bitrates))
goto drop;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index e0191f0..dcc0ffc 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -228,6 +228,7 @@ struct sta_ampdu_mlme {
* "the" transmit rate
* @last_rx_rate_idx: rx status rate index of the last data packet
* @last_rx_rate_flag: rx status flag of the last data packet
+ * @last_rx_rate_vht_nss: rx status nss of last data packet
* @lock: used for locking all fields that require locking, see comments
* in the header file.
* @drv_unblock_wk: used for driver PS unblocking
@@ -344,7 +345,8 @@ struct sta_info {
unsigned long tx_fragments;
struct ieee80211_tx_rate last_tx_rate;
int last_rx_rate_idx;
- int last_rx_rate_flag;
+ u32 last_rx_rate_flag;
+ u8 last_rx_rate_vht_nss;
u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];

/*
--
1.8.0


2012-11-12 10:55:12

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

On Fri, 2012-11-09 at 21:17 +0100, Johannes Berg wrote:

> + case NL80211_CHAN_WIDTH_80P80:
> + width = 80;
> + if (!vht_cap->vht_supported)
> return -EINVAL;
> + break;
> + case NL80211_CHAN_WIDTH_80:
> + width = 80;
> + if (!vht_cap->vht_supported)
> + return -EINVAL;
> + if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))
> + return -EINVAL;

Just noticed & fixed the capability check bug here :)

johannes


2012-11-18 11:03:17

by Johannes Berg

[permalink] [raw]
Subject: Re: VHT support, take 2

On Sat, 2012-11-17 at 15:34 -0800, Luis R. Rodriguez wrote:

> > > The only thing mentioned which I had not considered is the per bandwidth
> > > TX power restrictions. Where did these come from ?
> >
> > As usual, they come from the regulations :-)
>
> Which one in particular decided to add per bandwidth
> TX power restrictions for VHT ?

German regulations have always had bandwidth restrictions, we've just
fuzzed around it by restricting it to the lowest common power between 20
and 40 MHz bandwidth.

johannes


2012-11-19 08:32:59

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

On Mon, 2012-11-19 at 09:48 +0530, Mahesh Palivela wrote:

> >> Should we have NL80211_CHAN_WIDTH_LEGACY or rename
> >> NL80211_CHAN_WIDTH_20_NOHT to NL80211_CHAN_WIDTH_NOHT to cover non HT
> >> associations in both 2.4 & 5 GHz bands.
> >
> > Huh? I must be misunderstanding something -- both 2.4 and 5 GHz bands
> > use 20 MHz bandwidth by default?
> >
>
> 2.4 band channel spacing is 5 MHz and we can use 20 MHz bandwidth only
> in HT mode.

Umm, no.

johannes


2012-11-16 12:21:52

by Mahesh Palivela

[permalink] [raw]
Subject: Re: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

On 11/10/2012 01:47 AM, Johannes Berg wrote:
> From: Johannes Berg <[email protected]>
>

> + *
> + * @NL80211_CHAN_WIDTH_20_NOHT: 20 MHz, non-HT channel

Should we have NL80211_CHAN_WIDTH_LEGACY or rename
NL80211_CHAN_WIDTH_20_NOHT to NL80211_CHAN_WIDTH_NOHT to cover non HT
associations in both 2.4 & 5 GHz bands.

> + * @NL80211_CHAN_WIDTH_20: 20 MHz HT channel
> + * @NL80211_CHAN_WIDTH_40: 40 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
> + * attribute must be provided as well
> + * @NL80211_CHAN_WIDTH_80: 80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
> + * attribute must be provided as well
> + * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
> + * attribute must be provided as well
> + * @NL80211_CHAN_WIDTH_80P80: 80+80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
> + * and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well
> + */
> +enum nl80211_chan_width {
> + NL80211_CHAN_WIDTH_20_NOHT,
> + NL80211_CHAN_WIDTH_20,
> + NL80211_CHAN_WIDTH_40,
> + NL80211_CHAN_WIDTH_80,
> + NL80211_CHAN_WIDTH_160,
> + NL80211_CHAN_WIDTH_80P80,
> +};

2012-11-16 12:37:03

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

On Fri, 2012-11-16 at 17:51 +0530, Mahesh Palivela wrote:
> On 11/10/2012 01:47 AM, Johannes Berg wrote:
> > From: Johannes Berg <[email protected]>
> >
>
> > + *
> > + * @NL80211_CHAN_WIDTH_20_NOHT: 20 MHz, non-HT channel
>
> Should we have NL80211_CHAN_WIDTH_LEGACY or rename
> NL80211_CHAN_WIDTH_20_NOHT to NL80211_CHAN_WIDTH_NOHT to cover non HT
> associations in both 2.4 & 5 GHz bands.

Huh? I must be misunderstanding something -- both 2.4 and 5 GHz bands
use 20 MHz bandwidth by default?

johannes


2012-11-17 08:47:59

by Johannes Berg

[permalink] [raw]
Subject: Re: VHT support, take 2

On Fri, 2012-11-16 at 16:10 -0800, Luis R. Rodriguez wrote:

> > >Yeah, actually I'm not sure it's that easy. We'll also need per
> > >bandwidth TX power restrictions, raise the 40 MHz bandwidth restriction
> > >to 160 MHz (or get rid of it entirely), etc. That seems to require a new
> > >regulatory database format?
> >
> > Luis discussed the regulatory framework during the wireless summit
> > in Barcelona last week. My (possibly limited) recollection was that
> > the current regulatory code can accommodate VHT limits as well. I
> > assume that also includes the regulatory database format.
>
> The only thing mentioned which I had not considered is the per bandwidth
> TX power restrictions. Where did these come from ?

As usual, they come from the regulations :-)


2012-11-20 08:41:00

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 4/8] nl80211/cfg80211: support VHT channel configuration

On Tue, 2012-11-20 at 13:57 +0530, Mahesh Palivela wrote:

> > + for (freq = center_freq - bw/2 + 10;
> > + freq <= center_freq + bw/2 - 10;
> > + freq += 20) {
> > + c = ieee80211_get_channel(wiphy, freq);
> > + if (!c || c->flags & (IEEE80211_CHAN_DISABLED |
> > + IEEE80211_CHAN_PASSIVE_SCAN |
> > + IEEE80211_CHAN_NO_IBSS |
> > + IEEE80211_CHAN_RADAR))
> > + return false;


> > + for (freq = center_freq - bw/2 + 10;
> > + freq <= center_freq + bw/2 - 10;
> > + freq += 20) {
> > + c = ieee80211_get_channel(&rdev->wiphy, freq);
> > + if (!c || c->flags & IEEE80211_CHAN_DISABLED)
> > + return -EINVAL;


> For loops in both functions seems to be similar. One return false, other
> return -EINVAL. Can we remove duplication?

True, but they check different flags. I suppose we could have a common
function where the checked flags are passed in, I can try that.

johannes


2012-11-16 14:58:53

by Arend van Spriel

[permalink] [raw]
Subject: Re: VHT support, take 2

On 11/16/2012 02:28 PM, Johannes Berg wrote:
> On Thu, 2012-11-15 at 17:39 +0530, Mahesh Palivela wrote:
>
>> vht regulatory code already posted long back. After went through several
>> back n forth emails from Luis Rodriguez, accepted the patch.
>> But not commited anywhere.
>> Now I have to change that to match to new structs like chan_def etc from
>> the vht channel work patches you posted 5 days back.
>>
>> Also helper funcs to replace chan->flags bit checking to dynamically
>> check channel through regulatory
>
> Yeah, actually I'm not sure it's that easy. We'll also need per
> bandwidth TX power restrictions, raise the 40 MHz bandwidth restriction
> to 160 MHz (or get rid of it entirely), etc. That seems to require a new
> regulatory database format?

Luis discussed the regulatory framework during the wireless summit in
Barcelona last week. My (possibly limited) recollection was that the
current regulatory code can accommodate VHT limits as well. I assume
that also includes the regulatory database format.

Gr. AvS



2012-11-17 00:08:07

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: VHT support, take 2

On Fri, Nov 16, 2012 at 03:57:07PM +0100, Arend van Spriel wrote:
> On 11/16/2012 02:28 PM, Johannes Berg wrote:
> >On Thu, 2012-11-15 at 17:39 +0530, Mahesh Palivela wrote:
> >
> >>vht regulatory code already posted long back. After went through several
> >>back n forth emails from Luis Rodriguez, accepted the patch.
> >>But not commited anywhere.
> >>Now I have to change that to match to new structs like chan_def etc from
> >>the vht channel work patches you posted 5 days back.
> >>
> >>Also helper funcs to replace chan->flags bit checking to dynamically
> >>check channel through regulatory
> >
> >Yeah, actually I'm not sure it's that easy. We'll also need per
> >bandwidth TX power restrictions, raise the 40 MHz bandwidth restriction
> >to 160 MHz (or get rid of it entirely), etc. That seems to require a new
> >regulatory database format?
>
> Luis discussed the regulatory framework during the wireless summit
> in Barcelona last week. My (possibly limited) recollection was that
> the current regulatory code can accommodate VHT limits as well. I
> assume that also includes the regulatory database format.

The only thing mentioned which I had not considered is the per bandwidth
TX power restrictions. Where did these come from ?

Luis

2012-11-15 12:09:41

by Mahesh Palivela

[permalink] [raw]
Subject: Re: VHT support, take 2

On 11/10/2012 01:51 AM, Johannes Berg wrote:
> On Fri, 2012-11-09 at 21:17 +0100, Johannes Berg wrote:
>
>> What I intend to do next is this have a patch to parse the VHT
>> operation IE in mac80211 (or have a helper in cfg80211?) to
>> select the VHT channel configuration in MLME code.
>>
>> I'm kinda hoping the posedge folks will come back with the
>> regulatory code so I don't have to worry about that ...
>> *hint hint* :-)

vht regulatory code already posted long back. After went through several
back n forth emails from Luis Rodriguez, accepted the patch.
But not commited anywhere.
Now I have to change that to match to new structs like chan_def etc from
the vht channel work patches you posted 5 days back.

Also helper funcs to replace chan->flags bit checking to dynamically
check channel through regulatory

>>
>> After that, I'll need to work on the remaining hostapd code,
>> that should just need channel configuration etc. now. Then I
>> think it just needs a good test run.
>>
>> I'm not interested in VHT IBSS, so I'm not going to do anything
>> there, nor VHT mesh.
>>
>> The other thing would be rate control, e.g. minstrel_vht, but
>> I'm not sure we can use minstrel at all, so I'll probalby not
>> work on minstrel myself.
>
> Oh and then of course there's also a whole bunch of action frame
> handling that will be needed in mac80211, but I'm not really sure yet
> what that actually is.
>
> johannes
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>

2012-11-09 20:17:05

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2 8/8] mac80211: support VHT rates in TX info

From: Johannes Berg <[email protected]>

To achieve this, limit the number of retries to
31 (instead of 255) and use the three bits that
are then free for VHT flags.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/mac80211.h | 44 +++++++++++++++++++++++++++++++++++++-------
net/mac80211/cfg.c | 41 ++++++++++++++++++++++++-----------------
2 files changed, 61 insertions(+), 24 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index da9fcd6..d1fa1ef 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -499,9 +499,14 @@ enum mac80211_tx_control_flags {
* This is set if the current BSS requires ERP protection.
* @IEEE80211_TX_RC_USE_SHORT_PREAMBLE: Use short preamble.
* @IEEE80211_TX_RC_MCS: HT rate.
+ * @IEEE80211_TX_RC_VHT_MCS: VHT MCS rate, in this case the idx field is split
+ * into a higher 4 bits (Nss) and lower 4 bits (MCS number)
* @IEEE80211_TX_RC_GREEN_FIELD: Indicates whether this rate should be used in
* Greenfield mode.
* @IEEE80211_TX_RC_40_MHZ_WIDTH: Indicates if the Channel Width should be 40 MHz.
+ * @IEEE80211_TX_RC_80_MHZ_WIDTH: Indicates 80 MHz transmission
+ * @IEEE80211_TX_RC_160_MHZ_WIDTH: Indicates 160 MHz transmission
+ * (80+80 isn't supported yet)
* @IEEE80211_TX_RC_DUP_DATA: The frame should be transmitted on both of the
* adjacent 20 MHz channels, if the current channel type is
* NL80211_CHAN_HT40MINUS or NL80211_CHAN_HT40PLUS.
@@ -512,12 +517,15 @@ enum mac80211_rate_control_flags {
IEEE80211_TX_RC_USE_CTS_PROTECT = BIT(1),
IEEE80211_TX_RC_USE_SHORT_PREAMBLE = BIT(2),

- /* rate index is an MCS rate number instead of an index */
+ /* rate index is an HT/VHT MCS instead of an index */
IEEE80211_TX_RC_MCS = BIT(3),
- IEEE80211_TX_RC_GREEN_FIELD = BIT(4),
- IEEE80211_TX_RC_40_MHZ_WIDTH = BIT(5),
- IEEE80211_TX_RC_DUP_DATA = BIT(6),
- IEEE80211_TX_RC_SHORT_GI = BIT(7),
+ IEEE80211_TX_RC_VHT_MCS = BIT(4),
+ IEEE80211_TX_RC_GREEN_FIELD = BIT(5),
+ IEEE80211_TX_RC_40_MHZ_WIDTH = BIT(6),
+ IEEE80211_TX_RC_80_MHZ_WIDTH = BIT(7),
+ IEEE80211_TX_RC_160_MHZ_WIDTH = BIT(8),
+ IEEE80211_TX_RC_DUP_DATA = BIT(9),
+ IEEE80211_TX_RC_SHORT_GI = BIT(10),
};


@@ -560,10 +568,32 @@ enum mac80211_rate_control_flags {
*/
struct ieee80211_tx_rate {
s8 idx;
- u8 count;
- u8 flags;
+ u16 count:5,
+ flags:11;
} __packed;

+#define IEEE80211_MAX_TX_RETRY 31
+
+static inline void ieee80211_rate_set_vht(struct ieee80211_tx_rate *rate,
+ u8 mcs, u8 nss)
+{
+ WARN_ON(mcs & ~0xF);
+ WARN_ON(nss & ~0x7);
+ rate->idx = (nss << 4) | mcs;
+}
+
+static inline u8
+ieee80211_rate_get_vht_mcs(const struct ieee80211_tx_rate *rate)
+{
+ return rate->idx & 0xF;
+}
+
+static inline u8
+ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate)
+{
+ return rate->idx >> 4;
+}
+
/**
* struct ieee80211_tx_info - skb transmit information
*
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 5e9fdce..665b393 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -370,31 +370,32 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy,
return 0;
}

-static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx)
-{
- enum ieee80211_band band = ieee80211_get_sdata_band(sta->sdata);
-
- if (!(rate->flags & RATE_INFO_FLAGS_MCS) &&
- !(rate->flags & RATE_INFO_FLAGS_VHT_MCS)) {
- struct ieee80211_supported_band *sband;
- sband = sta->local->hw.wiphy->bands[band];
- rate->legacy = sband->bitrates[idx].bitrate;
- } else
- rate->mcs = idx;
-}
-
void sta_set_rate_info_tx(struct sta_info *sta,
const struct ieee80211_tx_rate *rate,
struct rate_info *rinfo)
{
rinfo->flags = 0;
- if (rate->flags & IEEE80211_TX_RC_MCS)
+ if (rate->flags & IEEE80211_TX_RC_MCS) {
rinfo->flags |= RATE_INFO_FLAGS_MCS;
+ rinfo->mcs = rate->idx;
+ } else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
+ rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS;
+ rinfo->mcs = ieee80211_rate_get_vht_mcs(rate);
+ rinfo->nss = ieee80211_rate_get_vht_nss(rate);
+ } else {
+ struct ieee80211_supported_band *sband;
+ sband = sta->local->hw.wiphy->bands[
+ ieee80211_get_sdata_band(sta->sdata)];
+ rinfo->legacy = sband->bitrates[rate->idx].bitrate;
+ }
if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+ rinfo->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
+ if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
+ rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
- rate_idx_to_bitrate(rinfo, sta, rate->idx);
}

static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
@@ -2030,10 +2031,16 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
return err;
}

- if (changed & WIPHY_PARAM_RETRY_SHORT)
+ if (changed & WIPHY_PARAM_RETRY_SHORT) {
+ if (wiphy->retry_short > IEEE80211_MAX_TX_RETRY)
+ return -EINVAL;
local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
- if (changed & WIPHY_PARAM_RETRY_LONG)
+ }
+ if (changed & WIPHY_PARAM_RETRY_LONG) {
+ if (wiphy->retry_long > IEEE80211_MAX_TX_RETRY)
+ return -EINVAL;
local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
+ }
if (changed &
(WIPHY_PARAM_RETRY_SHORT | WIPHY_PARAM_RETRY_LONG))
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS);
--
1.8.0