2012-07-27 11:17:00

by Johannes Berg

[permalink] [raw]
Subject: [RFC 00/20] mac80211: multi-channel work

Building on Michal's work for channel contexts, which I've
kept as the first few patches (some of them modified for a
few small fixes), this actually makes mac80211 support more
than a single channel. How many channels is determined by
the driver and verified by cfg80211, so mac80211 isn't much
involved there.

Internally, mac80211 will exclusively use channel contexts.
It then has some compatibility code that will call the old
config() method of the driver, if the driver isn't updated
to take advantage of channel contexts.

In order to support multi-channel, drivers must:
* implement the five new channel context methods
* be able to offload scanning
* be able to offload remain-on-channel

Trying to advertise multiple channels without support for
channel context methods is an error, advertising multiple
channels without support for scan/roc causes all scan/roc
operations to always fail.

So far, I've only tested this with hwsim, and even then
only the backward compatibility code to make sure that it
won't break drivers that aren't updated. I've tested that
channel contexts are added/removed properly and that the
configuration is updated in the device. I've also tested
with two virtual interfaces to see that compatible channel
types are still possible and result in the desired driver
methods being called.

Comments welcome!

johannes



2012-07-27 11:42:42

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 18/20] mac80211: allow drv_add_chanctx to fail

On Fri, 2012-07-27 at 13:42 +0200, Michal Kazior wrote:
> On 27/07/12 13:16, Johannes Berg wrote:
> > --- a/net/mac80211/chan.c
> > +++ b/net/mac80211/chan.c
> > @@ -237,7 +237,10 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
> >
> > list_add(&ctx->list, &local->chanctx_list);
> >
> > - drv_add_chanctx(local, ctx);
> > + if (drv_add_chanctx(local, ctx)) {
> > + kfree(ctx);
>
> We should also do a list_del() here.

Good catch. Or just move the list_add() later?

johannes


2012-07-27 11:17:03

by Johannes Berg

[permalink] [raw]
Subject: [RFC 06/20] mac80211: refactor set_channel_type

From: Michal Kazior <[email protected]>

Split functionality for further reuse.

Will prevent code duplication when channel context
channel_type merging is introduced.

Signed-off-by: Michal Kazior <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/chan.c | 67 ++++++++++++++++++++++++++++++++++++---------------
1 file changed, 48 insertions(+), 19 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 8d77ad13..90fef15 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -69,16 +69,14 @@ ieee80211_get_channel_mode(struct ieee80211_local *local,
return mode;
}

-bool ieee80211_set_channel_type(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- enum nl80211_channel_type chantype)
+static enum nl80211_channel_type
+ieee80211_get_superchan(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
{
- struct ieee80211_sub_if_data *tmp;
enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT;
- bool result;
+ struct ieee80211_sub_if_data *tmp;

mutex_lock(&local->iflist_mtx);
-
list_for_each_entry(tmp, &local->interfaces, list) {
if (tmp == sdata)
continue;
@@ -104,41 +102,72 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local,
break;
}
}
+ mutex_unlock(&local->iflist_mtx);
+
+ return superchan;
+}

- switch (superchan) {
+static bool
+ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1,
+ enum nl80211_channel_type chantype2,
+ enum nl80211_channel_type *compat)
+{
+ /*
+ * 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 (chantype == NL80211_CHAN_NO_HT)
+ if (chantype2 == NL80211_CHAN_NO_HT)
break;
- superchan = chantype;
+ if (compat)
+ *compat = chantype2;
break;
case NL80211_CHAN_HT40PLUS:
case NL80211_CHAN_HT40MINUS:
/* allow smaller bandwidth and same */
- if (chantype == NL80211_CHAN_NO_HT)
+ if (chantype2 == NL80211_CHAN_NO_HT)
break;
- if (chantype == NL80211_CHAN_HT20)
+ if (chantype2 == NL80211_CHAN_HT20)
break;
- if (superchan == chantype)
+ if (chantype2 == chantype1)
break;
- result = false;
- goto out;
+ return false;
}

- local->_oper_channel_type = superchan;
+ return true;
+}
+
+bool ieee80211_set_channel_type(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ enum nl80211_channel_type chantype)
+{
+ enum nl80211_channel_type superchan;
+ enum nl80211_channel_type compatchan = NL80211_CHAN_NO_HT;
+
+ superchan = ieee80211_get_superchan(local, sdata);
+ if (!ieee80211_channel_types_are_compatible(superchan, chantype,
+ &compatchan))
+ return false;
+
+ local->_oper_channel_type = compatchan;

if (sdata)
sdata->vif.bss_conf.channel_type = chantype;

- result = true;
- out:
- mutex_unlock(&local->iflist_mtx);
+ return true;

- return result;
}

static struct ieee80211_chanctx *
--
1.7.10.4


2012-07-27 11:46:23

by Michal Kazior

[permalink] [raw]
Subject: Re: [RFC 20/20] mac80211: use channel contexts

On 27/07/12 13:16, Johannes Berg wrote:
> diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
> index d062085..bf2bc19 100644
> --- a/net/mac80211/ibss.c
> +++ b/net/mac80211/ibss.c
> @@ -26,7 +26,6 @@
> #include "rate.h"
>
> #define IEEE80211_SCAN_INTERVAL (2 * HZ)
> -#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)
> #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ)
>
> #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
> @@ -80,17 +79,15 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
>
> sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
>
> - local->oper_channel = chan;
> channel_type = ifibss->channel_type;
> if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
> channel_type = NL80211_CHAN_HT20;
> - if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
> - /* can only fail due to HT40+/- mismatch */
> - channel_type = NL80211_CHAN_HT20;
> - WARN_ON(!ieee80211_set_channel_type(local, sdata,
> - NL80211_CHAN_HT20));
> - }
> - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
> +
> + ieee80211_vif_release_channel(sdata);
> + ieee80211_vif_use_channel(sdata, chan, channel_type,
> + ifibss->fixed_channel ?
> + IEEE80211_CHANCTX_SHARED :
> + IEEE80211_CHANCTX_EXCLUSIVE);

ieee80211_vif_use_channel() may fail. Can we just ignore it here?


-- Pozdrawiam / Best regards, Michal Kazior.

2012-07-27 11:42:03

by Michal Kazior

[permalink] [raw]
Subject: Re: [RFC 18/20] mac80211: allow drv_add_chanctx to fail

On 27/07/12 13:16, Johannes Berg wrote:
> --- a/net/mac80211/chan.c
> +++ b/net/mac80211/chan.c
> @@ -237,7 +237,10 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
>
> list_add(&ctx->list, &local->chanctx_list);
>
> - drv_add_chanctx(local, ctx);
> + if (drv_add_chanctx(local, ctx)) {
> + kfree(ctx);

We should also do a list_del() here.


> + return NULL;
> + }
>
> return ctx;
> }


-- Pozdrawiam / Best regards, Michal Kazior.

2012-07-27 11:45:13

by Michal Kazior

[permalink] [raw]
Subject: Re: [RFC 18/20] mac80211: allow drv_add_chanctx to fail

On 27/07/12 13:42, Johannes Berg wrote:
> On Fri, 2012-07-27 at 13:42 +0200, Michal Kazior wrote:
>> On 27/07/12 13:16, Johannes Berg wrote:
>>> --- a/net/mac80211/chan.c
>>> +++ b/net/mac80211/chan.c
>>> @@ -237,7 +237,10 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
>>>
>>> list_add(&ctx->list, &local->chanctx_list);
>>>
>>> - drv_add_chanctx(local, ctx);
>>> + if (drv_add_chanctx(local, ctx)) {
>>> + kfree(ctx);
>>
>> We should also do a list_del() here.
>
> Good catch. Or just move the list_add() later?

Yes, that'll work too.


-- Pozdrawiam / Best regards, Michal Kazior.

2012-07-27 11:17:45

by Johannes Berg

[permalink] [raw]
Subject: [RFC 19/20] mac80211: return error code from ieee80211_vif_use_channel

From: Johannes Berg <[email protected]>

Instead of returning a bool successful value, return a
regular error code that could come from the driver.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/chan.c | 22 ++++++++++++----------
net/mac80211/ieee80211_i.h | 8 ++++----
2 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 2c7c975..0542123 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -223,12 +223,13 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
enum ieee80211_chanctx_mode mode)
{
struct ieee80211_chanctx *ctx;
+ int err;

lockdep_assert_held(&local->chanctx_mtx);

ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
if (!ctx)
- return NULL;
+ return ERR_PTR(-ENOMEM);

ctx->conf.channel = channel;
ctx->conf.channel_type = channel_type;
@@ -237,9 +238,10 @@ ieee80211_new_chanctx(struct ieee80211_local *local,

list_add(&ctx->list, &local->chanctx_list);

- if (drv_add_chanctx(local, ctx)) {
+ err = drv_add_chanctx(local, ctx);
+ if (err) {
kfree(ctx);
- return NULL;
+ return ERR_PTR(err);
}

return ctx;
@@ -340,10 +342,10 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
ieee80211_free_chanctx(local, ctx);
}

-bool ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type,
- enum ieee80211_chanctx_mode mode)
+int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type,
+ enum ieee80211_chanctx_mode mode)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx *ctx;
@@ -354,14 +356,14 @@ bool ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
ctx = ieee80211_find_chanctx(local, channel, channel_type, mode);
if (!ctx)
ctx = ieee80211_new_chanctx(local, channel, channel_type, mode);
- if (!ctx) {
+ if (IS_ERR(ctx)) {
mutex_unlock(&local->chanctx_mtx);
- return false;
+ return PTR_ERR(ctx);
}

ieee80211_assign_vif_chanctx(sdata, ctx);
mutex_unlock(&local->chanctx_mtx);
- return true;
+ return 0;
}

void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c52db65..f8cce7d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1543,10 +1543,10 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local,
enum nl80211_channel_type
ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper);

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

#ifdef CONFIG_MAC80211_NOINLINE
--
1.7.10.4


2012-07-27 11:17:50

by Johannes Berg

[permalink] [raw]
Subject: [RFC 13/20] mac80211: use RX status band instead of current band

From: Johannes Berg <[email protected]>

Even for single-channel devices it is possible that we
switch the channel temporarily (e.g. for scanning) but
while doing so process a received frame that was still
received on the old channel, so checking the current
band is racy. Use the band from status instead.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/rx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 3b74232..5983d3e 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2268,7 +2268,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)

goto queue;
case WLAN_CATEGORY_SPECTRUM_MGMT:
- if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
+ if (status->band != IEEE80211_BAND_5GHZ)
break;

if (sdata->vif.type != NL80211_IFTYPE_STATION)
--
1.7.10.4


2012-07-27 11:18:00

by Johannes Berg

[permalink] [raw]
Subject: [RFC 16/20] mac80211: check channel context methods

From: Johannes Berg <[email protected]>

Verify that the channel context methods are
all assigned by the driver or not used.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/main.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 820f717..96abcf2 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -553,6 +553,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove)))
return NULL;

+ /* check all or no channel context operations exist */
+ i = !!ops->add_chanctx + !!ops->remove_chanctx +
+ !!ops->change_chantype + !!ops->assign_vif_chanctx +
+ !!ops->unassign_vif_chanctx;
+ if (WARN_ON(i != 0 && i != 5))
+ return NULL;
+
/* Ensure 32-byte alignment of our private data and hw private data.
* We use the wiphy priv data for both our ieee80211_local and for
* the driver's private data
--
1.7.10.4


2012-07-27 11:17:04

by Johannes Berg

[permalink] [raw]
Subject: [RFC 08/20] mac80211: mesh: don't use global channel type

From: Johannes Berg <[email protected]>

Using local->_oper_channel_type in the mesh code is
completely wrong as this value is the combination
of the various interface channel types and can be
a different value from the mesh interface in case
there are multiple virtual interfaces.

Use sdata->vif.bss_conf.channel_type instead as it
tracks the per-vif channel type.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/mesh.c | 11 ++++++-----
net/mac80211/mesh_plink.c | 7 ++++---
2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index e6d1788..62d93ab 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -109,11 +109,11 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,

/* Disallow HT40+/- mismatch */
if (ie->ht_operation &&
- (local->_oper_channel_type == NL80211_CHAN_HT40MINUS ||
- local->_oper_channel_type == NL80211_CHAN_HT40PLUS) &&
+ (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) &&
- local->_oper_channel_type != sta_channel_type)
+ sdata->vif.bss_conf.channel_type != sta_channel_type)
goto mismatch;

return true;
@@ -375,7 +375,7 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb,

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

if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap))
@@ -392,7 +392,8 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb,
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_channel *channel = local->oper_channel;
- enum nl80211_channel_type channel_type = local->_oper_channel_type;
+ enum nl80211_channel_type channel_type =
+ sdata->vif.bss_conf.channel_type;
struct ieee80211_supported_band *sband =
local->hw.wiphy->bands[channel->band];
struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 6df9fc0..a203166 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 (local->_oper_channel_type == NL80211_CHAN_NO_HT)
+ if (sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
return 0;

rcu_read_lock();
@@ -147,7 +147,8 @@ out:

if (non_ht_sta)
ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED;
- else if (ht20_sta && local->_oper_channel_type > NL80211_CHAN_HT20)
+ else if (ht20_sta &&
+ sdata->vif.bss_conf.channel_type > NL80211_CHAN_HT20)
ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ;
else
ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
@@ -370,7 +371,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->local->_oper_channel_type != NL80211_CHAN_NO_HT)
+ sdata->vif.bss_conf.channel_type != NL80211_CHAN_NO_HT)
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
elems->ht_cap_elem,
&sta->sta.ht_cap);
--
1.7.10.4


2012-07-27 11:17:02

by Johannes Berg

[permalink] [raw]
Subject: [RFC 05/20] mac80211: use channel context notifications

From: Michal Kazior <[email protected]>

Channel context pointer will be accessible on
both assign and unassign events.

Signed-off-by: Michal Kazior <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/chan.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 184b8bd..8d77ad13 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -5,6 +5,7 @@
#include <linux/nl80211.h>
#include <net/cfg80211.h>
#include "ieee80211_i.h"
+#include "driver-ops.h"

static enum ieee80211_chan_mode
__ieee80211_get_channel_mode(struct ieee80211_local *local,
@@ -190,6 +191,8 @@ ieee80211_new_chanctx(struct ieee80211_local *local,

list_add(&ctx->list, &local->chanctx_list);

+ drv_add_chanctx(local, ctx);
+
return ctx;
}

@@ -200,6 +203,8 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,

WARN_ON_ONCE(ctx->refcount != 0);

+ drv_remove_chanctx(ctx->local, ctx);
+
list_del(&ctx->list);
kfree(ctx);
}
@@ -207,21 +212,25 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
static void ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx *ctx)
{
- struct ieee80211_local *local __maybe_unused = sdata->local;
+ struct ieee80211_local *local = sdata->local;

lockdep_assert_held(&local->chanctx_mtx);

sdata->vif.chanctx_conf = &ctx->conf;
ctx->refcount++;
+
+ drv_assign_vif_chanctx(local, sdata, ctx);
}

static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx *ctx)
{
- struct ieee80211_local *local __maybe_unused = sdata->local;
+ struct ieee80211_local *local = sdata->local;

lockdep_assert_held(&local->chanctx_mtx);

+ drv_unassign_vif_chanctx(local, sdata, ctx);
+
ctx->refcount--;
sdata->vif.chanctx_conf = NULL;
}
--
1.7.10.4


2012-07-27 18:08:10

by Joe Perches

[permalink] [raw]
Subject: Re: [RFC 03/20] mac80211: add drv_* wrappers for channel contexts

On Fri, 2012-07-27 at 13:16 +0200, Johannes Berg wrote:
> From: Michal Kazior <[email protected]>
[]
> diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
[]
> @@ -866,4 +866,50 @@ static inline void drv_mgd_prepare_tx(struct ieee80211_local *local,
[]
> +static inline void drv_add_chanctx(struct ieee80211_local *local,
> + struct ieee80211_chanctx *ctx)
> +{
> + if (local->ops->add_chanctx)
> + local->ops->add_chanctx(&local->hw, &ctx->conf);

Perhaps these repeated function names should be some macro
to avoid typos or copy/paste errors.

Maybe something like:

#define local_op(func, ...) \
do { \
if (local->ops->func) \
local->ops->func(##__VA_ARGS__); \
} while (0)

So the uses become:

local_op(add_chanctx, &local->hw, &ctx->conf);

> +static inline void drv_remove_chanctx(struct ieee80211_local *local,
> + struct ieee80211_chanctx *ctx)
> +{
> + if (local->ops->remove_chanctx)
> + local->ops->remove_chanctx(&local->hw, &ctx->conf);

local_op(remove_chanctx, &local->hw, &ctx->conf);

etc...



2012-07-27 11:17:54

by Johannes Berg

[permalink] [raw]
Subject: [RFC 12/20] mac80211: don't assume channel is set in tracing

From: Johannes Berg <[email protected]>

With the move to multi-channel and away from
drv_config(), hw.conf.channel will not always
be set, only for devices using the current API
instead of the new channel context APIs. Check
the channel is set before adding its frequency
to the trace data.

Also break some overly long lines in the code.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/trace.h | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index a0cd3cb..6004ea7 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -274,9 +274,12 @@ TRACE_EVENT(drv_config,
__entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout;
__entry->max_sleep_period = local->hw.conf.max_sleep_period;
__entry->listen_interval = local->hw.conf.listen_interval;
- __entry->long_frame_max_tx_count = local->hw.conf.long_frame_max_tx_count;
- __entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count;
- __entry->center_freq = local->hw.conf.channel->center_freq;
+ __entry->long_frame_max_tx_count =
+ local->hw.conf.long_frame_max_tx_count;
+ __entry->short_frame_max_tx_count =
+ local->hw.conf.short_frame_max_tx_count;
+ __entry->center_freq = local->hw.conf.channel ?
+ local->hw.conf.channel->center_freq : 0;
__entry->channel_type = local->hw.conf.channel_type;
__entry->smps = local->hw.conf.smps_mode;
),
--
1.7.10.4


2012-07-27 11:17:58

by Johannes Berg

[permalink] [raw]
Subject: [RFC 14/20] mac80211: check operating channel in scan

From: Johannes Berg <[email protected]>

The optimisation of scanning only on the current
channel should check the operating channel. Also
modify it to compare channel pointer rather than
the frequency.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/scan.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index e80a8b6..0045869 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -480,11 +480,10 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
if (local->ops->hw_scan) {
__set_bit(SCAN_HW_SCANNING, &local->scanning);
} else if ((req->n_channels == 1) &&
- (req->channels[0]->center_freq ==
- local->hw.conf.channel->center_freq)) {
-
- /* If we are scanning only on the current channel, then
- * we do not need to stop normal activities
+ (req->channels[0] == local->oper_channel)) {
+ /*
+ * If we are scanning only on the operating channel
+ * then we do not need to stop normal activities
*/
unsigned long next_delay;

--
1.7.10.4


2012-07-29 09:03:11

by Eliad Peller

[permalink] [raw]
Subject: Re: [RFC 06/20] mac80211: refactor set_channel_type

On Fri, Jul 27, 2012 at 2:16 PM, Johannes Berg
<[email protected]> wrote:
> From: Michal Kazior <[email protected]>
>
> Split functionality for further reuse.
>
> Will prevent code duplication when channel context
> channel_type merging is introduced.
>
> Signed-off-by: Michal Kazior <[email protected]>
> Signed-off-by: Johannes Berg <[email protected]>
> ---

> +
> +bool ieee80211_set_channel_type(struct ieee80211_local *local,
> + struct ieee80211_sub_if_data *sdata,
> + enum nl80211_channel_type chantype)
> +{
> + enum nl80211_channel_type superchan;
> + enum nl80211_channel_type compatchan = NL80211_CHAN_NO_HT;
> +
no need to initialize compatchan.

> + superchan = ieee80211_get_superchan(local, sdata);
> + if (!ieee80211_channel_types_are_compatible(superchan, chantype,
> + &compatchan))
> + return false;
> +

as it should be assigned here.

Eliad.

2012-07-27 11:17:03

by Johannes Berg

[permalink] [raw]
Subject: [RFC 07/20] mac80211: reuse channels for channel contexts

From: Michal Kazior <[email protected]>

Reuse channels with compatible channel types. Some
channel types are compatible and can be used
concurrently.

Signed-off-by: Michal Kazior <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/chan.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 57 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 90fef15..40e707c 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -167,7 +167,17 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local,
sdata->vif.bss_conf.channel_type = chantype;

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)
+ return;

+ ctx->conf.channel_type = chantype;
+ drv_change_chantype(local, ctx);
}

static struct ieee80211_chanctx *
@@ -177,6 +187,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
enum ieee80211_chanctx_mode mode)
{
struct ieee80211_chanctx *ctx;
+ enum nl80211_channel_type compat_type;

lockdep_assert_held(&local->chanctx_mtx);

@@ -186,13 +197,19 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
return NULL;

list_for_each_entry(ctx, &local->chanctx_list, list) {
+ compat_type = ctx->conf.channel_type;
+
if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
continue;
if (ctx->conf.channel != channel)
continue;
- if (ctx->conf.channel_type != channel_type)
+ if (!ieee80211_channel_types_are_compatible(ctx->conf.channel_type,
+ channel_type,
+ &compat_type))
continue;

+ ieee80211_change_chantype(local, ctx, compat_type);
+
return ctx;
}

@@ -251,6 +268,43 @@ static void ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
drv_assign_vif_chanctx(local, sdata, ctx);
}

+static enum nl80211_channel_type
+ieee80211_calc_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;
+
+ 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 (sdata->vif.chanctx_conf != conf)
+ continue;
+
+ WARN_ON_ONCE(!ieee80211_channel_types_are_compatible(
+ sdata->vif.bss_conf.channel_type,
+ result, &result));
+ }
+ 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);
+
+ chantype = ieee80211_calc_chantype(local, ctx);
+ ieee80211_change_chantype(local, ctx, chantype);
+}
+
static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx *ctx)
{
@@ -262,6 +316,8 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,

ctx->refcount--;
sdata->vif.chanctx_conf = NULL;
+
+ ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
}

static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
--
1.7.10.4


2012-07-27 11:17:02

by Johannes Berg

[permalink] [raw]
Subject: [RFC 04/20] mac80211: add chanctx tracing

From: Michal Kazior <[email protected]>

Signed-off-by: Michal Kazior <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/driver-ops.h | 10 ++++++
net/mac80211/trace.h | 88 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 98 insertions(+)

diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index b38f97d..da0fa69 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -870,22 +870,28 @@ static inline void drv_mgd_prepare_tx(struct ieee80211_local *local,
static inline void drv_add_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
+ trace_drv_add_chanctx(local, ctx);
if (local->ops->add_chanctx)
local->ops->add_chanctx(&local->hw, &ctx->conf);
+ trace_drv_return_void(local);
}

static inline void drv_remove_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
+ trace_drv_remove_chanctx(local, ctx);
if (local->ops->remove_chanctx)
local->ops->remove_chanctx(&local->hw, &ctx->conf);
+ trace_drv_return_void(local);
}

static inline void drv_change_chantype(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
+ trace_drv_change_chantype(local, ctx);
if (local->ops->change_chantype)
local->ops->change_chantype(&local->hw, &ctx->conf);
+ trace_drv_return_void(local);
}

static inline void drv_assign_vif_chanctx(struct ieee80211_local *local,
@@ -894,10 +900,12 @@ static inline void drv_assign_vif_chanctx(struct ieee80211_local *local,
{
check_sdata_in_driver(sdata);

+ trace_drv_assign_vif_chanctx(local, sdata, ctx);
if (local->ops->assign_vif_chanctx)
local->ops->assign_vif_chanctx(&local->hw,
&sdata->vif,
&ctx->conf);
+ trace_drv_return_void(local);
}

static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
@@ -906,10 +914,12 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
{
check_sdata_in_driver(sdata);

+ trace_drv_unassign_vif_chanctx(local, sdata, ctx);
if (local->ops->unassign_vif_chanctx)
local->ops->unassign_vif_chanctx(&local->hw,
&sdata->vif,
&ctx->conf);
+ trace_drv_return_void(local);
}

#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 65e9a2a..a0cd3cb 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -1253,6 +1253,94 @@ DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx,
TP_ARGS(local, sdata)
);

+DECLARE_EVENT_CLASS(local_chanctx,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx),
+
+ TP_ARGS(local, ctx),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(void *, ctx)
+ __field(int, freq)
+ __field(int, chantype)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ctx = ctx;
+ __entry->freq = ctx->conf.channel->center_freq;
+ __entry->chantype = ctx->conf.channel_type;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " ctx:%p freq:%dMhz chantype:%d",
+ LOCAL_PR_ARG, __entry->ctx, __entry->freq, __entry->chantype
+ )
+);
+
+DEFINE_EVENT(local_chanctx, drv_add_chanctx,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx),
+ TP_ARGS(local, ctx)
+);
+
+DEFINE_EVENT(local_chanctx, drv_remove_chanctx,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx),
+ TP_ARGS(local, ctx)
+);
+
+DEFINE_EVENT(local_chanctx, drv_change_chantype,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx),
+ TP_ARGS(local, ctx)
+);
+
+DECLARE_EVENT_CLASS(local_sdata_chanctx,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_chanctx *ctx),
+
+ TP_ARGS(local, sdata, ctx),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __field(void *, ctx)
+ __field(int, freq)
+ __field(int, chantype)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ __entry->ctx = ctx;
+ __entry->freq = ctx->conf.channel->center_freq;
+ __entry->chantype = ctx->conf.channel_type;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT " ctx:%p freq:%dMhz chantype:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG,
+ __entry->ctx, __entry->freq, __entry->chantype
+ )
+);
+
+DEFINE_EVENT(local_sdata_chanctx, drv_assign_vif_chanctx,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_chanctx *ctx),
+ TP_ARGS(local, sdata, ctx)
+);
+
+DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_chanctx *ctx),
+ TP_ARGS(local, sdata, ctx)
+);
+
/*
* Tracing for API calls that drivers call.
*/
--
1.7.10.4


2012-07-27 11:17:01

by Johannes Berg

[permalink] [raw]
Subject: [RFC 02/20] mac80211: introduce new ieee80211_ops

From: Michal Kazior <[email protected]>

Introduces channel context callbacks. Channel on a
context channel is immutable. Channel type will be
changeable later though, thus change_chantype is
advertised.

Signed-off-by: Michal Kazior <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
include/net/mac80211.h | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 6d19726..969eb20 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2292,6 +2292,16 @@ enum ieee80211_rate_control_changed {
* The callback will be called before each transmission and upon return
* mac80211 will transmit the frame right away.
* The callback is optional and can (should!) sleep.
+ *
+ * @add_chanctx: Notifies device driver about new channel context creation.
+ * @remove_chanctx: Notifies device driver about channel context destruction.
+ * @change_chantype: Notifies device driver about channel context channel_type
+ * change which may happen when combining different vifs on a same channel
+ * with different HTs.
+ * @assign_vif_chanctx: Notifies device driver about channel context being bound
+ * to vif. Possible use is for hw queue remapping.
+ * @unassign_vif_chanctx: Notifies device driver about channel context being
+ * unbound from vif.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -2434,6 +2444,19 @@ struct ieee80211_ops {

void (*mgd_prepare_tx)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
+
+ void (*add_chanctx)(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx);
+ void (*remove_chanctx)(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx);
+ void (*change_chantype)(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx);
+ void (*assign_vif_chanctx)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_chanctx_conf *ctx);
+ void (*unassign_vif_chanctx)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_chanctx_conf *ctx);
};

/**
--
1.7.10.4


2012-07-27 11:17:49

by Johannes Berg

[permalink] [raw]
Subject: [RFC 10/20] mac80211: remove freq/chantype from debugfs

From: Johannes Berg <[email protected]>

You can now get these values through iw, and
they conflict with multi-channel work.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/debugfs.c | 32 --------------------------------
1 file changed, 32 deletions(-)

diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index b8dfb44..97173f8 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -63,8 +63,6 @@ DEBUGFS_READONLY_FILE(user_power, "%d",
local->user_power_level);
DEBUGFS_READONLY_FILE(power, "%d",
local->hw.conf.power_level);
-DEBUGFS_READONLY_FILE(frequency, "%d",
- local->hw.conf.channel->center_freq);
DEBUGFS_READONLY_FILE(total_ps_buffered, "%d",
local->total_ps_buffered);
DEBUGFS_READONLY_FILE(wep_iv, "%#08x",
@@ -91,33 +89,6 @@ static const struct file_operations reset_ops = {
.llseek = noop_llseek,
};

-static ssize_t channel_type_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_local *local = file->private_data;
- const char *buf;
-
- switch (local->hw.conf.channel_type) {
- case NL80211_CHAN_NO_HT:
- buf = "no ht\n";
- break;
- case NL80211_CHAN_HT20:
- buf = "ht20\n";
- break;
- case NL80211_CHAN_HT40MINUS:
- buf = "ht40-\n";
- break;
- case NL80211_CHAN_HT40PLUS:
- buf = "ht40+\n";
- break;
- default:
- buf = "???";
- break;
- }
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
-}
-
static ssize_t hwflags_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -205,7 +176,6 @@ static ssize_t queues_read(struct file *file, char __user *user_buf,
}

DEBUGFS_READONLY_FILE_OPS(hwflags);
-DEBUGFS_READONLY_FILE_OPS(channel_type);
DEBUGFS_READONLY_FILE_OPS(queues);

/* statistics stuff */
@@ -272,12 +242,10 @@ void debugfs_hw_add(struct ieee80211_local *local)

local->debugfs.keys = debugfs_create_dir("keys", phyd);

- DEBUGFS_ADD(frequency);
DEBUGFS_ADD(total_ps_buffered);
DEBUGFS_ADD(wep_iv);
DEBUGFS_ADD(queues);
DEBUGFS_ADD_MODE(reset, 0200);
- DEBUGFS_ADD(channel_type);
DEBUGFS_ADD(hwflags);
DEBUGFS_ADD(user_power);
DEBUGFS_ADD(power);
--
1.7.10.4


2012-07-27 11:17:51

by Johannes Berg

[permalink] [raw]
Subject: [RFC 15/20] mac80211: convert ops checks to WARN_ON

From: Johannes Berg <[email protected]>

There's no need to BUG_ON when a driver registers
invalid operations, warn and return an error.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/main.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index f74e52a..820f717 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -545,6 +545,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
int priv_size, i;
struct wiphy *wiphy;

+ if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config ||
+ !ops->add_interface || !ops->remove_interface ||
+ !ops->configure_filter))
+ return NULL;
+
if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove)))
return NULL;

@@ -597,13 +602,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,

local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);

- BUG_ON(!ops->tx);
- BUG_ON(!ops->start);
- BUG_ON(!ops->stop);
- BUG_ON(!ops->config);
- BUG_ON(!ops->add_interface);
- BUG_ON(!ops->remove_interface);
- BUG_ON(!ops->configure_filter);
local->ops = ops;

/* set up some defaults */
--
1.7.10.4


2012-07-27 11:17:01

by Johannes Berg

[permalink] [raw]
Subject: [RFC 03/20] mac80211: add drv_* wrappers for channel contexts

From: Michal Kazior <[email protected]>

Signed-off-by: Michal Kazior <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/driver-ops.h | 46 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)

diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 597a474..b38f97d 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -866,4 +866,50 @@ static inline void drv_mgd_prepare_tx(struct ieee80211_local *local,
local->ops->mgd_prepare_tx(&local->hw, &sdata->vif);
trace_drv_return_void(local);
}
+
+static inline void drv_add_chanctx(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx)
+{
+ if (local->ops->add_chanctx)
+ local->ops->add_chanctx(&local->hw, &ctx->conf);
+}
+
+static inline void drv_remove_chanctx(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx)
+{
+ if (local->ops->remove_chanctx)
+ local->ops->remove_chanctx(&local->hw, &ctx->conf);
+}
+
+static inline void drv_change_chantype(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx)
+{
+ if (local->ops->change_chantype)
+ local->ops->change_chantype(&local->hw, &ctx->conf);
+}
+
+static inline void drv_assign_vif_chanctx(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_chanctx *ctx)
+{
+ check_sdata_in_driver(sdata);
+
+ if (local->ops->assign_vif_chanctx)
+ local->ops->assign_vif_chanctx(&local->hw,
+ &sdata->vif,
+ &ctx->conf);
+}
+
+static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_chanctx *ctx)
+{
+ check_sdata_in_driver(sdata);
+
+ if (local->ops->unassign_vif_chanctx)
+ local->ops->unassign_vif_chanctx(&local->hw,
+ &sdata->vif,
+ &ctx->conf);
+}
+
#endif /* __MAC80211_DRIVER_OPS */
--
1.7.10.4


2012-07-27 11:18:02

by Johannes Berg

[permalink] [raw]
Subject: [RFC 20/20] mac80211: use channel contexts

From: Johannes Berg <[email protected]>

Instead of operating on a single channel only,
use the new channel context infrastructure in
all mac80211 code.

This enables drivers that want to use the new
channel context infrastructure to use multiple
channels, while nothing should change for all
the other drivers that don't support it.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/cfg.c | 169 +++++++++++++++-----------------------------
net/mac80211/chan.c | 147 ++++++--------------------------------
net/mac80211/ibss.c | 48 +++----------
net/mac80211/ieee80211_i.h | 16 +----
net/mac80211/iface.c | 17 +----
net/mac80211/main.c | 34 ++++++---
net/mac80211/mesh.c | 11 +--
net/mac80211/mesh_plink.c | 6 +-
net/mac80211/mlme.c | 57 ++++++++-------
net/mac80211/rate.h | 7 +-
net/mac80211/scan.c | 2 +-
net/mac80211/tx.c | 8 ++-
net/mac80211/util.c | 8 ++-
13 files changed, 173 insertions(+), 357 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 7422ebc..90fbb66 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -342,7 +342,7 @@ static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, in
if (!(rate->flags & RATE_INFO_FLAGS_MCS)) {
struct ieee80211_supported_band *sband;
sband = sta->local->hw.wiphy->bands[
- sta->local->oper_channel->band];
+ sta->sdata->vif.chanctx_conf->channel->band];
rate->legacy = sband->bitrates[idx].bitrate;
} else
rate->mcs = idx;
@@ -574,19 +574,17 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
do_survey:
i = STA_STATS_LEN - STA_STATS_SURVEY_LEN;
/* Get survey stats for current channel */
- q = 0;
- while (true) {
- survey.filled = 0;
- if (drv_get_survey(local, q, &survey) != 0) {
+ survey.filled = 0;
+ if (sdata->vif.chanctx_conf) {
+ q = 0;
+ do {
survey.filled = 0;
- break;
- }
-
- if (survey.channel &&
- (local->oper_channel->center_freq ==
- survey.channel->center_freq))
- break;
- q++;
+ if (drv_get_survey(local, q, &survey) != 0) {
+ survey.filled = 0;
+ break;
+ }
+ q++;
+ } while (sdata->vif.chanctx_conf->channel != survey.channel);
}

if (survey.filled)
@@ -691,47 +689,12 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
return ret;
}

-static int ieee80211_set_channel(struct wiphy *wiphy,
- struct net_device *netdev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type)
-{
- struct ieee80211_local *local = wiphy_priv(wiphy);
- struct ieee80211_sub_if_data *sdata = NULL;
-
- if (netdev)
- sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
-
- switch (ieee80211_get_channel_mode(local, NULL)) {
- case CHAN_MODE_HOPPING:
- return -EBUSY;
- case CHAN_MODE_FIXED:
- if (local->oper_channel != chan ||
- (!sdata && local->_oper_channel_type != channel_type))
- return -EBUSY;
- if (!sdata && local->_oper_channel_type == channel_type)
- return 0;
- break;
- case CHAN_MODE_UNDEFINED:
- break;
- }
-
- if (!ieee80211_set_channel_type(local, sdata, channel_type))
- return -EBUSY;
-
- local->oper_channel = chan;
-
- /* auto-detects changes */
- ieee80211_hw_config(local, 0);
-
- return 0;
-}
-
static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type)
{
- return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
+ return 0;
+//return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
}

static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
@@ -848,8 +811,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
if (old)
return -EALREADY;

- err = ieee80211_set_channel(wiphy, dev, params->channel,
- params->channel_type);
+ err = ieee80211_vif_use_channel(sdata, params->channel,
+ params->channel_type,
+ IEEE80211_CHANCTX_SHARED);
if (err)
return err;

@@ -932,6 +896,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
sta_info_flush(sdata->local, sdata);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);

+ ieee80211_vif_release_channel(sdata);
+
return 0;
}

@@ -988,9 +954,10 @@ static int sta_apply_parameters(struct ieee80211_local *local,
int i, j;
struct ieee80211_supported_band *sband;
struct ieee80211_sub_if_data *sdata = sta->sdata;
+ enum ieee80211_band band = sdata->vif.chanctx_conf->channel->band;
u32 mask, set;

- sband = local->hw.wiphy->bands[local->oper_channel->band];
+ sband = local->hw.wiphy->bands[band];

mask = params->sta_flags_mask;
set = params->sta_flags_set;
@@ -1105,7 +1072,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
rates |= BIT(j);
}
}
- sta->sta.supp_rates[local->oper_channel->band] = rates;
+ sta->sta.supp_rates[band] = rates;
}

if (params->ht_capa)
@@ -1633,8 +1600,9 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
if (err)
return err;

- err = ieee80211_set_channel(wiphy, dev, setup->channel,
- setup->channel_type);
+ err = ieee80211_vif_use_channel(sdata, setup->channel,
+ setup->channel_type,
+ IEEE80211_CHANCTX_SHARED);
if (err)
return err;

@@ -1648,6 +1616,7 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);

ieee80211_stop_mesh(sdata);
+ ieee80211_vif_release_channel(sdata);

return 0;
}
@@ -1657,10 +1626,11 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
struct net_device *dev,
struct bss_parameters *params)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
u32 changed = 0;

- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (!rtnl_dereference(sdata->u.ap.beacon))
+ return -ENOENT;

if (params->use_cts_prot >= 0) {
sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
@@ -1673,7 +1643,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
}

if (!sdata->vif.bss_conf.use_short_slot &&
- sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) {
+ sdata->vif.chanctx_conf->channel->band == IEEE80211_BAND_5GHZ) {
sdata->vif.bss_conf.use_short_slot = true;
changed |= BSS_CHANGED_ERP_SLOT;
}
@@ -1687,9 +1657,8 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
if (params->basic_rates) {
int i, j;
u32 rates = 0;
- struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_supported_band *sband =
- wiphy->bands[local->oper_channel->band];
+ wiphy->bands[sdata->vif.chanctx_conf->channel->band];

for (i = 0; i < params->basic_rates_len; i++) {
int rate = (params->basic_rates[i] & 0x7f) * 5;
@@ -1841,20 +1810,6 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_assoc_request *req)
{
- struct ieee80211_local *local = wiphy_priv(wiphy);
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- switch (ieee80211_get_channel_mode(local, sdata)) {
- case CHAN_MODE_HOPPING:
- return -EBUSY;
- case CHAN_MODE_FIXED:
- if (local->oper_channel == req->bss->channel)
- break;
- return -EBUSY;
- case CHAN_MODE_UNDEFINED:
- break;
- }
-
return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
}

@@ -1873,30 +1828,12 @@ static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ibss_params *params)
{
- struct ieee80211_local *local = wiphy_priv(wiphy);
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- switch (ieee80211_get_channel_mode(local, sdata)) {
- case CHAN_MODE_HOPPING:
- return -EBUSY;
- case CHAN_MODE_FIXED:
- if (!params->channel_fixed)
- return -EBUSY;
- if (local->oper_channel == params->channel)
- break;
- return -EBUSY;
- case CHAN_MODE_UNDEFINED:
- break;
- }
-
- return ieee80211_ibss_join(sdata, params);
+ return ieee80211_ibss_join(IEEE80211_DEV_TO_SUB_IF(dev), params);
}

static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- return ieee80211_ibss_leave(sdata);
+ return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev));
}

static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
@@ -1940,9 +1877,13 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
enum nl80211_tx_power_setting type, int mbm)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
- struct ieee80211_channel *chan = local->oper_channel;
+ struct ieee80211_channel *chan = local->_oper_channel;
u32 changes = 0;

+ /* FIXME */
+ if (local->use_chanctx)
+ return -EOPNOTSUPP;
+
switch (type) {
case NL80211_TX_POWER_AUTOMATIC:
local->user_power_level = -1;
@@ -2488,10 +2429,14 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,

/* Check if the operating channel is the requested channel */
if (!need_offchan) {
- need_offchan = chan != local->oper_channel;
- if (channel_type_valid &&
- channel_type != local->_oper_channel_type)
+ if (sdata->vif.chanctx_conf) {
+ need_offchan = chan != sdata->vif.chanctx_conf->channel;
+ if (channel_type_valid &&
+ channel_type != sdata->vif.chanctx_conf->channel_type)
+ need_offchan = true;
+ } else {
need_offchan = true;
+ }
}

if (need_offchan && !offchan) {
@@ -2640,7 +2585,7 @@ static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata)
u16 capab;

capab = 0;
- if (local->oper_channel->band != IEEE80211_BAND_2GHZ)
+ if (sdata->vif.chanctx_conf->channel->band != IEEE80211_BAND_2GHZ)
return capab;

if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
@@ -2672,7 +2617,6 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
u16 status_code, struct sk_buff *skb)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_local *local = sdata->local;
struct ieee80211_tdls_data *tf;

tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
@@ -2693,9 +2637,9 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));

ieee80211_add_srates_ie(sdata, skb, false,
- local->oper_channel->band);
+ sdata->vif.chanctx_conf->channel->band);
ieee80211_add_ext_srates_ie(sdata, skb, false,
- local->oper_channel->band);
+ sdata->vif.chanctx_conf->channel->band);
ieee80211_tdls_add_ext_capab(skb);
break;
case WLAN_TDLS_SETUP_RESPONSE:
@@ -2709,9 +2653,9 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));

ieee80211_add_srates_ie(sdata, skb, false,
- local->oper_channel->band);
+ sdata->vif.chanctx_conf->channel->band);
ieee80211_add_ext_srates_ie(sdata, skb, false,
- local->oper_channel->band);
+ sdata->vif.chanctx_conf->channel->band);
ieee80211_tdls_add_ext_capab(skb);
break;
case WLAN_TDLS_SETUP_CONFIRM:
@@ -2749,7 +2693,6 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
u16 status_code, struct sk_buff *skb)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_local *local = sdata->local;
struct ieee80211_mgmt *mgmt;

mgmt = (void *)skb_put(skb, 24);
@@ -2773,9 +2716,9 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));

ieee80211_add_srates_ie(sdata, skb, false,
- local->oper_channel->band);
+ sdata->vif.chanctx_conf->channel->band);
ieee80211_add_ext_srates_ie(sdata, skb, false,
- local->oper_channel->band);
+ sdata->vif.chanctx_conf->channel->band);
ieee80211_tdls_add_ext_capab(skb);
break;
default:
@@ -3015,10 +2958,14 @@ static struct ieee80211_channel *
ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
enum nl80211_channel_type *type)
{
- struct ieee80211_local *local = wiphy_priv(wiphy);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+
+ if (sdata->vif.chanctx_conf) {
+ *type = sdata->vif.chanctx_conf->channel_type;
+ return sdata->vif.chanctx_conf->channel;
+ }

- *type = local->_oper_channel_type;
- return local->oper_channel;
+ return NULL;
}

#ifdef CONFIG_PM
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 0542123..88bae9e 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -7,106 +7,6 @@
#include "ieee80211_i.h"
#include "driver-ops.h"

-static enum ieee80211_chan_mode
-__ieee80211_get_channel_mode(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *ignore)
-{
- struct ieee80211_sub_if_data *sdata;
-
- lockdep_assert_held(&local->iflist_mtx);
-
- list_for_each_entry(sdata, &local->interfaces, list) {
- if (sdata == ignore)
- continue;
-
- if (!ieee80211_sdata_running(sdata))
- continue;
-
- switch (sdata->vif.type) {
- case NL80211_IFTYPE_MONITOR:
- continue;
- case NL80211_IFTYPE_STATION:
- if (!sdata->u.mgd.associated)
- continue;
- break;
- case NL80211_IFTYPE_ADHOC:
- if (!sdata->u.ibss.ssid_len)
- continue;
- if (!sdata->u.ibss.fixed_channel)
- return CHAN_MODE_HOPPING;
- break;
- case NL80211_IFTYPE_AP_VLAN:
- /* will also have _AP interface */
- continue;
- case NL80211_IFTYPE_AP:
- if (!sdata->u.ap.beacon)
- continue;
- break;
- case NL80211_IFTYPE_MESH_POINT:
- if (!sdata->wdev.mesh_id_len)
- continue;
- break;
- default:
- break;
- }
-
- return CHAN_MODE_FIXED;
- }
-
- return CHAN_MODE_UNDEFINED;
-}
-
-enum ieee80211_chan_mode
-ieee80211_get_channel_mode(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *ignore)
-{
- enum ieee80211_chan_mode mode;
-
- mutex_lock(&local->iflist_mtx);
- mode = __ieee80211_get_channel_mode(local, ignore);
- mutex_unlock(&local->iflist_mtx);
-
- return mode;
-}
-
-static enum nl80211_channel_type
-ieee80211_get_superchan(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata)
-{
- enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT;
- struct ieee80211_sub_if_data *tmp;
-
- mutex_lock(&local->iflist_mtx);
- list_for_each_entry(tmp, &local->interfaces, list) {
- if (tmp == sdata)
- continue;
-
- if (!ieee80211_sdata_running(tmp))
- continue;
-
- switch (tmp->vif.bss_conf.channel_type) {
- case NL80211_CHAN_NO_HT:
- case NL80211_CHAN_HT20:
- if (superchan > tmp->vif.bss_conf.channel_type)
- break;
-
- superchan = tmp->vif.bss_conf.channel_type;
- break;
- case NL80211_CHAN_HT40PLUS:
- WARN_ON(superchan == NL80211_CHAN_HT40MINUS);
- superchan = NL80211_CHAN_HT40PLUS;
- break;
- case NL80211_CHAN_HT40MINUS:
- WARN_ON(superchan == NL80211_CHAN_HT40PLUS);
- superchan = NL80211_CHAN_HT40MINUS;
- break;
- }
- }
- mutex_unlock(&local->iflist_mtx);
-
- return superchan;
-}
-
static bool
ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1,
enum nl80211_channel_type chantype2,
@@ -149,26 +49,6 @@ ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1,
return true;
}

-bool ieee80211_set_channel_type(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- enum nl80211_channel_type chantype)
-{
- enum nl80211_channel_type superchan;
- enum nl80211_channel_type compatchan = NL80211_CHAN_NO_HT;
-
- superchan = ieee80211_get_superchan(local, sdata);
- if (!ieee80211_channel_types_are_compatible(superchan, chantype,
- &compatchan))
- return false;
-
- local->_oper_channel_type = compatchan;
-
- if (sdata)
- sdata->vif.bss_conf.channel_type = chantype;
-
- return true;
-}
-
static void ieee80211_change_chantype(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
enum nl80211_channel_type chantype)
@@ -178,6 +58,11 @@ static void ieee80211_change_chantype(struct ieee80211_local *local,

ctx->conf.channel_type = chantype;
drv_change_chantype(local, ctx);
+
+ if (!local->use_chanctx) {
+ local->_oper_channel_type = chantype;
+ ieee80211_hw_config(local, 0);
+ }
}

static struct ieee80211_chanctx *
@@ -238,10 +123,16 @@ ieee80211_new_chanctx(struct ieee80211_local *local,

list_add(&ctx->list, &local->chanctx_list);

- err = drv_add_chanctx(local, ctx);
- if (err) {
- kfree(ctx);
- return ERR_PTR(err);
+ if (!local->use_chanctx) {
+ local->_oper_channel_type = channel_type;
+ local->_oper_channel = channel;
+ ieee80211_hw_config(local, 0);
+ } else {
+ err = drv_add_chanctx(local, ctx);
+ if (err) {
+ kfree(ctx);
+ return ERR_PTR(err);
+ }
}

return ctx;
@@ -254,7 +145,12 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,

WARN_ON_ONCE(ctx->refcount != 0);

- drv_remove_chanctx(ctx->local, ctx);
+ if (!local->use_chanctx) {
+ local->_oper_channel_type = NL80211_CHAN_NO_HT;
+ ieee80211_hw_config(local, 0);
+ } else {
+ drv_remove_chanctx(ctx->local, ctx);
+ }

list_del(&ctx->list);
kfree(ctx);
@@ -361,6 +257,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
return PTR_ERR(ctx);
}

+ sdata->vif.bss_conf.channel_type = channel_type;
ieee80211_assign_vif_chanctx(sdata, ctx);
mutex_unlock(&local->chanctx_mtx);
return 0;
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index d062085..bf2bc19 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -26,7 +26,6 @@
#include "rate.h"

#define IEEE80211_SCAN_INTERVAL (2 * HZ)
-#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)
#define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ)

#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
@@ -80,17 +79,15 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,

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

- local->oper_channel = chan;
channel_type = ifibss->channel_type;
if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
channel_type = NL80211_CHAN_HT20;
- if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
- /* can only fail due to HT40+/- mismatch */
- channel_type = NL80211_CHAN_HT20;
- WARN_ON(!ieee80211_set_channel_type(local, sdata,
- NL80211_CHAN_HT20));
- }
- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+
+ ieee80211_vif_release_channel(sdata);
+ ieee80211_vif_use_channel(sdata, chan, channel_type,
+ ifibss->fixed_channel ?
+ IEEE80211_CHANCTX_SHARED :
+ IEEE80211_CHANCTX_EXCLUSIVE);

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

@@ -294,7 +291,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
- int band = local->oper_channel->band;
+ int band = sdata->vif.chanctx_conf->channel->band;

/*
* XXX: Consider removing the least recently used entry and
@@ -485,10 +482,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
if (!(cbss->capability & WLAN_CAPABILITY_IBSS))
goto put_bss;

- /* different channel */
- if (cbss->channel != local->oper_channel)
- goto put_bss;
-
/* different SSID */
if (elems->ssid_len != sdata->u.ibss.ssid_len ||
memcmp(elems->ssid, sdata->u.ibss.ssid,
@@ -561,7 +554,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
- int band = local->oper_channel->band;
+ int band = sdata->vif.chanctx_conf->channel->band;

/*
* XXX: Consider removing the least recently used entry and
@@ -753,18 +746,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
int interval = IEEE80211_SCAN_INTERVAL;

if (time_after(jiffies, ifibss->ibss_join_req +
- IEEE80211_IBSS_JOIN_TIMEOUT)) {
- if (!(local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS)) {
- ieee80211_sta_create_ibss(sdata);
- return;
- }
- sdata_info(sdata, "IBSS not allowed on %d MHz\n",
- local->oper_channel->center_freq);
-
- /* No IBSS found - decrease scan interval and continue
- * scanning. */
- interval = IEEE80211_SCAN_INTERVAL_SLOW;
- }
+ IEEE80211_IBSS_JOIN_TIMEOUT))
+ ieee80211_sta_create_ibss(sdata);

mod_timer(&ifibss->timer,
round_jiffies(jiffies + interval));
@@ -1052,17 +1035,6 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
sdata->u.ibss.channel_type = params->channel_type;
sdata->u.ibss.fixed_channel = params->channel_fixed;

- /* fix ourselves to that channel now already */
- if (params->channel_fixed) {
- sdata->local->oper_channel = params->channel;
- if (!ieee80211_set_channel_type(sdata->local, sdata,
- params->channel_type)) {
- mutex_unlock(&sdata->u.ibss.mtx);
- kfree_skb(skb);
- return -EINVAL;
- }
- }
-
if (params->ie) {
sdata->u.ibss.ie = kmemdup(params->ie, params->ie_len,
GFP_KERNEL);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f8cce7d..7c79be8 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -998,8 +998,10 @@ struct ieee80211_local {
enum mac80211_scan_state next_scan_state;
struct delayed_work scan_work;
struct ieee80211_sub_if_data __rcu *scan_sdata;
+ struct ieee80211_channel *csa_channel;
+ /* For backward compatibility only -- do not use */
+ struct ieee80211_channel *_oper_channel;
enum nl80211_channel_type _oper_channel_type;
- struct ieee80211_channel *oper_channel, *csa_channel;

/* Temporary remain-on-channel for off-channel operations */
struct ieee80211_channel *tmp_channel;
@@ -1528,18 +1530,6 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
enum ieee80211_band band);

/* channel management */
-enum ieee80211_chan_mode {
- CHAN_MODE_UNDEFINED,
- CHAN_MODE_HOPPING,
- CHAN_MODE_FIXED,
-};
-
-enum ieee80211_chan_mode
-ieee80211_get_channel_mode(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *ignore);
-bool ieee80211_set_channel_type(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- enum nl80211_channel_type chantype);
enum nl80211_channel_type
ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper);

diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index ced8c6c..fa04d31 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -650,7 +650,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, *tmp;
u32 hw_reconf_flags = 0;
int i;
- enum nl80211_channel_type orig_ct;

clear_bit(SDATA_STATE_RUNNING, &sdata->state);

@@ -821,14 +820,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
hw_reconf_flags = 0;
}

- /* Re-calculate channel-type, in case there are multiple vifs
- * on different channel types.
- */
- orig_ct = local->_oper_channel_type;
- ieee80211_set_channel_type(local, NULL, NL80211_CHAN_NO_HT);
-
/* do after stop to avoid reconfiguring when we stop anyway */
- if (hw_reconf_flags || (orig_ct != local->_oper_channel_type))
+ if (hw_reconf_flags)
ieee80211_hw_config(local, hw_reconf_flags);

spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
@@ -1278,11 +1271,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
if (type == ieee80211_vif_type_p2p(&sdata->vif))
return 0;

- /* Setting ad-hoc mode on non-IBSS channel is not supported. */
- if (sdata->local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS &&
- type == NL80211_IFTYPE_ADHOC)
- return -EOPNOTSUPP;
-
if (ieee80211_sdata_running(sdata)) {
ret = ieee80211_runtime_change_iftype(sdata, type);
if (ret)
@@ -1294,9 +1282,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
}

/* reset some values that shouldn't be kept across type changes */
- sdata->vif.bss_conf.basic_rates =
- ieee80211_mandatory_rates(sdata->local,
- sdata->local->oper_channel->band);
sdata->drop_unencrypted = 0;
if (type == NL80211_IFTYPE_STATION)
sdata->u.mgd.use_4addr = false;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index c58b339..7e31c19 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -93,23 +93,21 @@ static void ieee80211_reconfig_filter(struct work_struct *work)
ieee80211_configure_filter(local);
}

-int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
+static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
{
struct ieee80211_channel *chan;
- int ret = 0;
+ u32 changed = 0;
int power;
enum nl80211_channel_type channel_type;
u32 offchannel_flag;

- might_sleep();
-
offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
if (local->scan_channel) {
chan = local->scan_channel;
/* If scanning on oper channel, use whatever channel-type
* is currently in use.
*/
- if (chan == local->oper_channel)
+ if (chan == local->_oper_channel)
channel_type = local->_oper_channel_type;
else
channel_type = NL80211_CHAN_NO_HT;
@@ -117,11 +115,11 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
chan = local->tmp_channel;
channel_type = local->tmp_channel_type;
} else {
- chan = local->oper_channel;
+ chan = local->_oper_channel;
channel_type = local->_oper_channel_type;
}

- if (chan != local->oper_channel ||
+ if (chan != local->_oper_channel ||
channel_type != local->_oper_channel_type)
local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
else
@@ -155,7 +153,8 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
else
power = local->power_constr_level ?
min(chan->max_power,
- (chan->max_reg_power - local->power_constr_level)) :
+ (chan->max_reg_power -
+ local->power_constr_level)) :
chan->max_power;

if (local->user_power_level >= 0)
@@ -166,6 +165,21 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
local->hw.conf.power_level = power;
}

+ return changed;
+}
+
+int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
+{
+ int ret = 0;
+
+ might_sleep();
+
+ if (!local->use_chanctx)
+ changed |= ieee80211_hw_conf_chan(local);
+ else
+ changed &= ~(IEEE80211_CONF_CHANGE_CHANNEL |
+ IEEE80211_CONF_CHANGE_POWER);
+
if (changed && local->open_count) {
ret = drv_config(local, changed);
/*
@@ -771,10 +785,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
sband = local->hw.wiphy->bands[band];
if (!sband)
continue;
- if (!local->oper_channel) {
+ if (!local->use_chanctx && !local->_oper_channel) {
/* init channel we're on */
local->hw.conf.channel =
- local->oper_channel = &sband->channels[0];
+ local->_oper_channel = &sband->channels[0];
local->hw.conf.channel_type = NL80211_CHAN_NO_HT;
}
channels += sband->n_channels;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 62d93ab..751b264 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -97,7 +97,8 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
(ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)))
goto mismatch;

- ieee80211_sta_get_rates(local, ie, local->oper_channel->band,
+ ieee80211_sta_get_rates(local, ie,
+ sdata->vif.chanctx_conf->channel->band,
&basic_rates);

if (sdata->vif.bss_conf.basic_rates != basic_rates)
@@ -349,7 +350,7 @@ int mesh_add_ds_params_ie(struct sk_buff *skb,
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
- struct ieee80211_channel *chan = local->oper_channel;
+ struct ieee80211_channel *chan = sdata->vif.chanctx_conf->channel;
u8 *pos;

if (skb_tailroom(skb) < 3)
@@ -373,7 +374,7 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb,
struct ieee80211_supported_band *sband;
u8 *pos;

- sband = local->hw.wiphy->bands[local->oper_channel->band];
+ sband = local->hw.wiphy->bands[sdata->vif.chanctx_conf->channel->band];
if (!sband->ht_cap.ht_supported ||
sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
return 0;
@@ -391,7 +392,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
- struct ieee80211_channel *channel = local->oper_channel;
+ struct ieee80211_channel *channel = sdata->vif.chanctx_conf->channel;
enum nl80211_channel_type channel_type =
sdata->vif.bss_conf.channel_type;
struct ieee80211_supported_band *sband =
@@ -605,7 +606,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
sdata->vif.bss_conf.basic_rates =
ieee80211_mandatory_rates(sdata->local,
- sdata->local->oper_channel->band);
+ sdata->vif.chanctx_conf->channel->band);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED |
BSS_CHANGED_HT |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index a203166..50436a0 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -260,9 +260,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
memcpy(pos + 2, &plid, 2);
}
if (ieee80211_add_srates_ie(sdata, skb, true,
- local->oper_channel->band) ||
+ sdata->vif.chanctx_conf->channel->band) ||
ieee80211_add_ext_srates_ie(sdata, skb, true,
- local->oper_channel->band) ||
+ sdata->vif.chanctx_conf->channel->band) ||
mesh_add_rsn_ie(skb, sdata) ||
mesh_add_meshid_ie(skb, sdata) ||
mesh_add_meshconf_ie(skb, sdata))
@@ -336,7 +336,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems)
{
struct ieee80211_local *local = sdata->local;
- enum ieee80211_band band = local->oper_channel->band;
+ enum ieee80211_band band = sdata->vif.chanctx_conf->channel->band;
struct ieee80211_supported_band *sband;
u32 rates, basic_rates = 0;
struct sta_info *sta;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 1ff157e..09bd992 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -180,20 +180,21 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *chan = sdata->vif.chanctx_conf->channel;
struct sta_info *sta;
u32 changed = 0;
u16 ht_opmode;
bool disable_40 = false;

- sband = local->hw.wiphy->bands[local->oper_channel->band];
+ sband = local->hw.wiphy->bands[chan->band];

switch (sdata->vif.bss_conf.channel_type) {
case NL80211_CHAN_HT40PLUS:
- if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40PLUS)
+ if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
disable_40 = true;
break;
case NL80211_CHAN_HT40MINUS:
- if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40MINUS)
+ if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
disable_40 = true;
break;
default:
@@ -361,11 +362,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
int i, count, rates_len, supp_rates_len;
u16 capab;
struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *chan = sdata->vif.chanctx_conf->channel;
u32 rates = 0;

lockdep_assert_held(&ifmgd->mtx);

- sband = local->hw.wiphy->bands[local->oper_channel->band];
+ sband = local->hw.wiphy->bands[chan->band];

if (assoc_data->supp_rates_len) {
/*
@@ -487,7 +489,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
*pos++ = WLAN_EID_PWR_CAPABILITY;
*pos++ = 2;
*pos++ = 0; /* min tx power */
- *pos++ = local->oper_channel->max_power; /* max tx power */
+ *pos++ = chan->max_power; /* max tx power */

/* 2. supported channels */
/* TODO: get this in reg domain format */
@@ -525,7 +527,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)

if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
- sband, local->oper_channel, ifmgd->ap_smps);
+ sband, chan, ifmgd->ap_smps);

if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
ieee80211_add_vht_ie(sdata, skb, sband);
@@ -688,6 +690,7 @@ static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
/* spectrum management related things */
static void ieee80211_chswitch_work(struct work_struct *work)
{
+#if TODO
struct ieee80211_sub_if_data *sdata =
container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -717,10 +720,12 @@ static void ieee80211_chswitch_work(struct work_struct *work)
out:
ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
mutex_unlock(&ifmgd->mtx);
+#endif
}

void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
{
+#if TODO
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_managed *ifmgd;

@@ -739,6 +744,7 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
}

ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
+#endif
}
EXPORT_SYMBOL(ieee80211_chswitch_done);

@@ -1264,7 +1270,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
}

use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME);
- if (sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ)
+ if (sdata->vif.chanctx_conf->channel->band == IEEE80211_BAND_5GHZ)
use_short_slot = true;

if (use_protection != bss_conf->use_cts_prot) {
@@ -1444,9 +1450,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
ieee80211_bss_info_change_notify(sdata, changed);

- /* channel(_type) changes are handled by ieee80211_hw_config */
- WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
- ieee80211_hw_config(local, 0);
+ ieee80211_vif_release_channel(sdata);

/* disassociated - set to defaults now */
ieee80211_set_wmm_default(sdata, false);
@@ -1669,7 +1673,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,

skb = ieee80211_build_probe_req(sdata, cbss->bssid,
(u32) -1,
- sdata->local->oper_channel,
+ sdata->vif.chanctx_conf->channel,
ssid + 2, ssid_len,
NULL, 0, true);

@@ -1769,6 +1773,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,

memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
+ ieee80211_vif_release_channel(sdata);
}

cfg80211_put_bss(auth_data->bss);
@@ -1995,6 +2000,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,

memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
+ ieee80211_vif_release_channel(sdata);
}

kfree(assoc_data);
@@ -2056,7 +2062,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
return false;
}

- sband = local->hw.wiphy->bands[local->oper_channel->band];
+ sband = local->hw.wiphy->bands[sdata->vif.chanctx_conf->channel->band];

if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
@@ -2351,7 +2357,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (baselen > len)
return;

- if (rx_status->freq != local->oper_channel->center_freq)
+ if (!sdata->vif.chanctx_conf)
+ return;
+
+ if (rx_status->freq != sdata->vif.chanctx_conf->channel->center_freq)
return;

if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon &&
@@ -2515,7 +2524,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
!(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) {
struct ieee80211_supported_band *sband;

- sband = local->hw.wiphy->bands[local->oper_channel->band];
+ sband = local->hw.wiphy->bands[
+ sdata->vif.chanctx_conf->channel->band];

changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation,
bssid, true);
@@ -3085,20 +3095,9 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
}
}

- if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
- /* can only fail due to HT40+/- mismatch */
- channel_type = NL80211_CHAN_HT20;
- sdata_info(sdata,
- "disabling 40 MHz due to multi-vif mismatch\n");
- ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
- WARN_ON(!ieee80211_set_channel_type(local, sdata,
- channel_type));
- }
-
- local->oper_channel = cbss->channel;
- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
-
- return 0;
+ ieee80211_vif_release_channel(sdata);
+ return ieee80211_vif_use_channel(sdata, cbss->channel, channel_type,
+ IEEE80211_CHANCTX_SHARED);
}

static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
@@ -3168,7 +3167,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.basic_rates = basic_rates;

/* cf. IEEE 802.11 9.2.12 */
- if (local->oper_channel->band == IEEE80211_BAND_2GHZ &&
+ if (cbss->channel->band == IEEE80211_BAND_2GHZ &&
have_higher_than_11mbit)
sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
else
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index 10de668..5505450 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -52,11 +52,16 @@ static inline void rate_control_rate_init(struct sta_info *sta)
struct ieee80211_sta *ista = &sta->sta;
void *priv_sta = sta->rate_ctrl_priv;
struct ieee80211_supported_band *sband;
+ struct ieee80211_chanctx_conf *chanctx_conf;

if (!ref)
return;

- sband = local->hw.wiphy->bands[local->oper_channel->band];
+ chanctx_conf = sta->sdata->vif.chanctx_conf;
+ if (WARN_ON(!chanctx_conf))
+ return;
+
+ sband = local->hw.wiphy->bands[chanctx_conf->channel->band];

ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 7ca3441..bc597d7 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -484,7 +484,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
if (local->ops->hw_scan) {
__set_bit(SCAN_HW_SCANNING, &local->scanning);
} else if ((req->n_channels == 1) &&
- (req->channels[0] == local->oper_channel)) {
+ (req->channels[0] == local->_oper_channel)) {
/*
* If we are scanning only on the operating channel
* then we do not need to stop normal activities
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 7da1fa5..2bb07f5 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2299,7 +2299,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
struct ieee80211_sub_if_data *sdata = NULL;
struct ieee80211_if_ap *ap = NULL;
struct beacon_data *beacon;
- enum ieee80211_band band = local->oper_channel->band;
+ enum ieee80211_band band;
struct ieee80211_tx_rate_control txrc;

rcu_read_lock();
@@ -2423,6 +2423,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
*pos++ = WLAN_EID_SSID;
*pos++ = 0x0;

+ band = sdata->vif.chanctx_conf->channel->band;
+
if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
mesh_add_ds_params_ie(skb, sdata) ||
ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
@@ -2440,6 +2442,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
goto out;
}

+ band = sdata->vif.chanctx_conf->channel->band;
+
info = IEEE80211_SKB_CB(skb);

info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
@@ -2704,7 +2708,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
info = IEEE80211_SKB_CB(skb);

tx.flags |= IEEE80211_TX_PS_BUFFERED;
- info->band = local->oper_channel->band;
+ info->band = sdata->vif.chanctx_conf->channel->band;

if (invoke_tx_handlers(&tx))
skb = NULL;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 4c8cd99..8cf9d8d 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -838,7 +838,9 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,

memset(&qparam, 0, sizeof(qparam));

- use_11b = (local->oper_channel->band == IEEE80211_BAND_2GHZ) &&
+ use_11b = (sdata->vif.chanctx_conf &&
+ sdata->vif.chanctx_conf->channel->band ==
+ IEEE80211_BAND_2GHZ) &&
!(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);

/*
@@ -918,7 +920,6 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
const size_t supp_rates_len,
const u8 *supp_rates)
{
- struct ieee80211_local *local = sdata->local;
int i, have_higher_than_11mbit = 0;

/* cf. IEEE 802.11 9.2.12 */
@@ -926,7 +927,8 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
if ((supp_rates[i] & 0x7f) * 5 > 110)
have_higher_than_11mbit = 1;

- if (local->oper_channel->band == IEEE80211_BAND_2GHZ &&
+ if (sdata->vif.chanctx_conf &&
+ sdata->vif.chanctx_conf->channel->band == IEEE80211_BAND_2GHZ &&
have_higher_than_11mbit)
sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
else
--
1.7.10.4


2012-07-27 11:17:53

by Johannes Berg

[permalink] [raw]
Subject: [RFC 11/20] mac80211: use oper_channel in rate init

From: Johannes Berg <[email protected]>

Using hw.conf.channel is wrong as it could be the
temporary channel if the station is added from the
workqueue while the device is already on another
channel. Use oper_channel instead.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/rate.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index 6e4fd32..10de668 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -56,7 +56,7 @@ static inline void rate_control_rate_init(struct sta_info *sta)
if (!ref)
return;

- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[local->oper_channel->band];

ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
--
1.7.10.4


2012-07-27 21:03:10

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 03/20] mac80211: add drv_* wrappers for channel contexts

On Fri, 2012-07-27 at 11:08 -0700, Joe Perches wrote:

> > +static inline void drv_add_chanctx(struct ieee80211_local *local,
> > + struct ieee80211_chanctx *ctx)
> > +{
> > + if (local->ops->add_chanctx)
> > + local->ops->add_chanctx(&local->hw, &ctx->conf);
>
> Perhaps these repeated function names should be some macro
> to avoid typos or copy/paste errors.
>
> Maybe something like:
>
> #define local_op(func, ...) \
> do { \
> if (local->ops->func) \
> local->ops->func(##__VA_ARGS__); \
> } while (0)
>
> So the uses become:
>
> local_op(add_chanctx, &local->hw, &ctx->conf);

Interesting idea, but no, it needs tracing -- look at the next patch in
the series. (and yes, you could play with macros to add tracing, but
that would certainly just obfuscate the code)

johannes


2012-07-27 12:31:13

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 00/20] mac80211: multi-channel work

On Fri, 2012-07-27 at 13:16 +0200, Johannes Berg wrote:

> Comments welcome!

I should've mentioned what's left to do for me:

* figure out channel-switch handling, right now it's just #if'ed out
* restore TX power settings, but should it be be per vif, per chanctx
or something else?
* test test test :)

johannes


2012-07-27 11:17:01

by Johannes Berg

[permalink] [raw]
Subject: [RFC 01/20] mac80211: introduce channel context skeleton code

From: Michal Kazior <[email protected]>

Channel context are the foundation for multi-channel
operation. They are are immutable and are re-created
(or re-used if other interfaces are bound to a certain
channel and a compatible channel type) on channel
switching.

This is an initial implementation and more features
will come in separate patches.

Signed-off-by: Michal Kazior <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
include/net/mac80211.h | 25 +++++++++
net/mac80211/chan.c | 134 ++++++++++++++++++++++++++++++++++++++++++++
net/mac80211/ieee80211_i.h | 34 +++++++++++
net/mac80211/main.c | 3 +
4 files changed, 196 insertions(+)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 924b6c1..6d19726 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -144,6 +144,24 @@ struct ieee80211_low_level_stats {
};

/**
+ * struct ieee80211_chanctx_conf - channel context that vifs may be tuned to
+ *
+ * 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
+ * @drv_priv: data area for driver use, will always be aligned to
+ * sizeof(void *), size is determined in hw information.
+ */
+struct ieee80211_chanctx_conf {
+ struct ieee80211_channel *channel;
+ enum nl80211_channel_type channel_type;
+
+ u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
+};
+
+/**
* enum ieee80211_bss_change - BSS change notification flags
*
* These flags are used with the bss_info_changed() callback
@@ -903,6 +921,8 @@ enum ieee80211_vif_flags {
* at runtime, mac80211 will never touch this field
* @hw_queue: hardware queue for each AC
* @cab_queue: content-after-beacon (DTIM beacon really) queue, AP mode only
+ * @chanctx_conf: will be %NULL before the interface is assigned to a channel
+ * context
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *).
*/
@@ -915,6 +935,8 @@ struct ieee80211_vif {
u8 cab_queue;
u8 hw_queue[IEEE80211_NUM_ACS];

+ struct ieee80211_chanctx_conf *chanctx_conf;
+
u32 driver_flags;

/* must be last */
@@ -1279,6 +1301,8 @@ enum ieee80211_hw_flags {
* within &struct ieee80211_vif.
* @sta_data_size: size (in bytes) of the drv_priv data area
* within &struct ieee80211_sta.
+ * @chanctx_data_size: size (in bytes) of the drv_priv data area
+ * within &struct ieee80211_chanctx_conf.
*
* @max_rates: maximum number of alternate rate retry stages the hw
* can handle.
@@ -1323,6 +1347,7 @@ struct ieee80211_hw {
int channel_change_time;
int vif_data_size;
int sta_data_size;
+ int chanctx_data_size;
int napi_weight;
u16 queues;
u16 max_listen_interval;
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index f0f87e5..184b8bd 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -139,3 +139,137 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local,

return result;
}
+
+static struct ieee80211_chanctx *
+ieee80211_find_chanctx(struct ieee80211_local *local,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type,
+ enum ieee80211_chanctx_mode mode)
+{
+ struct ieee80211_chanctx *ctx;
+
+ 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) {
+ if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
+ continue;
+ if (ctx->conf.channel != channel)
+ continue;
+ if (ctx->conf.channel_type != channel_type)
+ continue;
+
+ return ctx;
+ }
+
+ return NULL;
+}
+
+static struct ieee80211_chanctx *
+ieee80211_new_chanctx(struct ieee80211_local *local,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type,
+ enum ieee80211_chanctx_mode mode)
+{
+ struct ieee80211_chanctx *ctx;
+
+ lockdep_assert_held(&local->chanctx_mtx);
+
+ ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+
+ ctx->conf.channel = channel;
+ ctx->conf.channel_type = channel_type;
+ ctx->mode = mode;
+ ctx->local = local;
+
+ list_add(&ctx->list, &local->chanctx_list);
+
+ return ctx;
+}
+
+static void ieee80211_free_chanctx(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx)
+{
+ lockdep_assert_held(&local->chanctx_mtx);
+
+ WARN_ON_ONCE(ctx->refcount != 0);
+
+ list_del(&ctx->list);
+ kfree(ctx);
+}
+
+static void ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_chanctx *ctx)
+{
+ struct ieee80211_local *local __maybe_unused = sdata->local;
+
+ lockdep_assert_held(&local->chanctx_mtx);
+
+ sdata->vif.chanctx_conf = &ctx->conf;
+ ctx->refcount++;
+}
+
+static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_chanctx *ctx)
+{
+ struct ieee80211_local *local __maybe_unused = sdata->local;
+
+ lockdep_assert_held(&local->chanctx_mtx);
+
+ ctx->refcount--;
+ sdata->vif.chanctx_conf = NULL;
+}
+
+static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_chanctx_conf *conf = sdata->vif.chanctx_conf;
+ struct ieee80211_chanctx *ctx =
+ container_of(conf, struct ieee80211_chanctx, conf);
+
+ lockdep_assert_held(&local->chanctx_mtx);
+
+ if (!conf)
+ return;
+
+ ieee80211_unassign_vif_chanctx(sdata, ctx);
+ if (ctx->refcount == 0)
+ ieee80211_free_chanctx(local, ctx);
+}
+
+bool ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type,
+ enum ieee80211_chanctx_mode mode)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_chanctx *ctx;
+
+ mutex_lock(&local->chanctx_mtx);
+ __ieee80211_vif_release_channel(sdata);
+
+ ctx = ieee80211_find_chanctx(local, channel, channel_type, mode);
+ if (!ctx)
+ ctx = ieee80211_new_chanctx(local, channel, channel_type, mode);
+ if (!ctx) {
+ mutex_unlock(&local->chanctx_mtx);
+ return false;
+ }
+
+ ieee80211_assign_vif_chanctx(sdata, ctx);
+ mutex_unlock(&local->chanctx_mtx);
+ return true;
+}
+
+void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
+{
+ mutex_lock(&sdata->local->chanctx_mtx);
+ __ieee80211_vif_release_channel(sdata);
+ mutex_unlock(&sdata->local->chanctx_mtx);
+}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8608704..4ad715d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -649,6 +649,30 @@ enum ieee80211_sdata_state_bits {
SDATA_STATE_OFFCHANNEL,
};

+/**
+ * enum ieee80211_chanctx_mode - channel context configuration mode
+ *
+ * @IEEE80211_CHANCTX_SHARED: channel context may be used by
+ * multiple interfaces
+ * @IEEE80211_CHANCTX_EXCLUSIVE: channel context can be used
+ * only by a single interface. This can be used for example for
+ * non-fixed channel IBSS.
+ */
+enum ieee80211_chanctx_mode {
+ IEEE80211_CHANCTX_SHARED,
+ IEEE80211_CHANCTX_EXCLUSIVE
+};
+
+struct ieee80211_chanctx {
+ struct list_head list;
+
+ struct ieee80211_local *local;
+ enum ieee80211_chanctx_mode mode;
+ int refcount;
+
+ struct ieee80211_chanctx_conf conf;
+};
+
struct ieee80211_sub_if_data {
struct list_head list;

@@ -979,6 +1003,10 @@ struct ieee80211_local {
struct ieee80211_channel *tmp_channel;
enum nl80211_channel_type tmp_channel_type;

+ /* channel contexts */
+ struct list_head chanctx_list;
+ struct mutex chanctx_mtx;
+
/* SNMP counters */
/* dot11CountersTable */
u32 dot11TransmittedFragmentCount;
@@ -1513,6 +1541,12 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local,
enum nl80211_channel_type
ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper);

+bool ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type,
+ enum ieee80211_chanctx_mode mode);
+void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
+
#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
#else
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index e706f9e..f74e52a 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -632,6 +632,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
spin_lock_init(&local->filter_lock);
spin_lock_init(&local->queue_stop_reason_lock);

+ INIT_LIST_HEAD(&local->chanctx_list);
+ mutex_init(&local->chanctx_mtx);
+
/*
* The rx_skb_queue is only accessed from tasklets,
* but other SKB queues are used from within IRQ
--
1.7.10.4


2012-07-27 11:17:47

by Johannes Berg

[permalink] [raw]
Subject: [RFC 17/20] mac80211: track whether to use channel contexts

From: Johannes Berg <[email protected]>

Depending on the driver, channel contexts may be used or
not. If they are used, the driver must have support for
hardware scan and remain-on-channel; otherwise the driver
must not advertise support for multiple channels.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/cfg.c | 3 +++
net/mac80211/ieee80211_i.h | 2 ++
net/mac80211/main.c | 14 ++++++++++++++
net/mac80211/offchannel.c | 6 ++++++
net/mac80211/scan.c | 4 ++++
5 files changed, 29 insertions(+)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 1910517..7422ebc 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2159,6 +2159,9 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,

lockdep_assert_held(&local->mtx);

+ if (local->use_chanctx && !local->ops->remain_on_channel)
+ return -EOPNOTSUPP;
+
roc = kzalloc(sizeof(*roc), GFP_KERNEL);
if (!roc)
return -ENOMEM;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4ad715d..c52db65 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -873,6 +873,8 @@ struct ieee80211_local {

bool wiphy_ciphers_allocated;

+ bool use_chanctx;
+
/* protects the aggregated multicast list and filter calls */
spinlock_t filter_lock;

diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 96abcf2..c58b339 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -544,6 +544,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
struct ieee80211_local *local;
int priv_size, i;
struct wiphy *wiphy;
+ bool use_chanctx;

if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config ||
!ops->add_interface || !ops->remove_interface ||
@@ -559,6 +560,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
!!ops->unassign_vif_chanctx;
if (WARN_ON(i != 0 && i != 5))
return NULL;
+ use_chanctx = i == 5;

/* Ensure 32-byte alignment of our private data and hw private data.
* We use the wiphy priv data for both our ieee80211_local and for
@@ -610,6 +612,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);

local->ops = ops;
+ local->use_chanctx = use_chanctx;

/* set up some defaults */
local->hw.queues = 1;
@@ -733,6 +736,17 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan)
return -EINVAL;

+ if (!local->use_chanctx) {
+ for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
+ const struct ieee80211_iface_combination *comb;
+
+ comb = &local->hw.wiphy->iface_combinations[i];
+
+ if (comb->num_different_channels > 1)
+ return -EINVAL;
+ }
+ }
+
/* Only HW csum features are currently compatible with mac80211 */
feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_HW_CSUM;
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 507121d..4970660 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -107,6 +107,9 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
{
struct ieee80211_sub_if_data *sdata;

+ if (WARN_ON(local->use_chanctx))
+ return;
+
/*
* notify the AP about us leaving the channel and stop all
* STA interfaces.
@@ -145,6 +148,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
{
struct ieee80211_sub_if_data *sdata;

+ if (WARN_ON(local->use_chanctx))
+ return;
+
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 0045869..7ca3441 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -337,6 +337,10 @@ EXPORT_SYMBOL(ieee80211_scan_completed);

static int ieee80211_start_sw_scan(struct ieee80211_local *local)
{
+ /* Software scan is not supported in multi-channel cases */
+ if (local->use_chanctx)
+ return -EOPNOTSUPP;
+
/*
* Hardware/driver doesn't support hw_scan, so use software
* scanning instead. First send a nullfunc frame with power save
--
1.7.10.4


2012-07-27 11:17:56

by Johannes Berg

[permalink] [raw]
Subject: [RFC 18/20] mac80211: allow drv_add_chanctx to fail

From: Johannes Berg <[email protected]>

The driver might need to do some operations to the
device that could fail, so allow drv_add_chanctx()
to fail and propagate that error.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/mac80211.h | 4 ++--
net/mac80211/chan.c | 5 ++++-
net/mac80211/driver-ops.h | 12 ++++++++----
3 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 969eb20..a3c647c 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2445,8 +2445,8 @@ struct ieee80211_ops {
void (*mgd_prepare_tx)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);

- void (*add_chanctx)(struct ieee80211_hw *hw,
- struct ieee80211_chanctx_conf *ctx);
+ int (*add_chanctx)(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx);
void (*remove_chanctx)(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx);
void (*change_chantype)(struct ieee80211_hw *hw,
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 40e707c..2c7c975 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -237,7 +237,10 @@ ieee80211_new_chanctx(struct ieee80211_local *local,

list_add(&ctx->list, &local->chanctx_list);

- drv_add_chanctx(local, ctx);
+ if (drv_add_chanctx(local, ctx)) {
+ kfree(ctx);
+ return NULL;
+ }

return ctx;
}
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index da0fa69..bca963a 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -867,13 +867,17 @@ static inline void drv_mgd_prepare_tx(struct ieee80211_local *local,
trace_drv_return_void(local);
}

-static inline void drv_add_chanctx(struct ieee80211_local *local,
- struct ieee80211_chanctx *ctx)
+static inline int drv_add_chanctx(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx)
{
+ int ret = -EOPNOTSUPP;
+
trace_drv_add_chanctx(local, ctx);
if (local->ops->add_chanctx)
- local->ops->add_chanctx(&local->hw, &ctx->conf);
- trace_drv_return_void(local);
+ ret = local->ops->add_chanctx(&local->hw, &ctx->conf);
+ trace_drv_return_int(local, ret);
+
+ return ret;
}

static inline void drv_remove_chanctx(struct ieee80211_local *local,
--
1.7.10.4


2012-07-27 11:17:04

by Johannes Berg

[permalink] [raw]
Subject: [RFC 09/20] mac80211: remove almost unused local variable

From: Johannes Berg <[email protected]>

In ieee80211_beacon_get_tim() we can use the
txrc.sband instead of a separate local variable.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/tx.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 385c280..7da1fa5 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2299,12 +2299,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
struct ieee80211_sub_if_data *sdata = NULL;
struct ieee80211_if_ap *ap = NULL;
struct beacon_data *beacon;
- struct ieee80211_supported_band *sband;
enum ieee80211_band band = local->oper_channel->band;
struct ieee80211_tx_rate_control txrc;

- sband = local->hw.wiphy->bands[band];
-
rcu_read_lock();

sdata = vif_to_sdata(vif);
@@ -2451,12 +2448,12 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,

memset(&txrc, 0, sizeof(txrc));
txrc.hw = hw;
- txrc.sband = sband;
+ txrc.sband = local->hw.wiphy->bands[band];
txrc.bss_conf = &sdata->vif.bss_conf;
txrc.skb = skb;
txrc.reported_rate.idx = -1;
txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
- if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1)
+ if (txrc.rate_idx_mask == (1 << txrc.sband->n_bitrates) - 1)
txrc.max_rate_idx = -1;
else
txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
--
1.7.10.4


2012-07-27 11:55:39

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 20/20] mac80211: use channel contexts

On Fri, 2012-07-27 at 13:46 +0200, Michal Kazior wrote:

> > @@ -80,17 +79,15 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
> >
> > sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
> >
> > - local->oper_channel = chan;
> > channel_type = ifibss->channel_type;
> > if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
> > channel_type = NL80211_CHAN_HT20;
> > - if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
> > - /* can only fail due to HT40+/- mismatch */
> > - channel_type = NL80211_CHAN_HT20;
> > - WARN_ON(!ieee80211_set_channel_type(local, sdata,
> > - NL80211_CHAN_HT20));
> > - }
> > - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
> > +
> > + ieee80211_vif_release_channel(sdata);
> > + ieee80211_vif_use_channel(sdata, chan, channel_type,
> > + ifibss->fixed_channel ?
> > + IEEE80211_CHANCTX_SHARED :
> > + IEEE80211_CHANCTX_EXCLUSIVE);
>
> ieee80211_vif_use_channel() may fail. Can we just ignore it here?

No, I guess we shouldn't, though it's an exclusive channel context most
of the time, so it shouldn't fail. I'll fix this, not really sure what
to do about it though.

johannes


2012-08-26 08:36:36

by Eliad Peller

[permalink] [raw]
Subject: Re: [RFC 00/20] mac80211: multi-channel work

On Sun, Aug 26, 2012 at 11:30 AM, Johannes Berg
<[email protected]> wrote:
> On Sun, 2012-08-26 at 11:28 +0300, Eliad Peller wrote:
>
>> >> this scenario (deauth after disassoc) also sounds pretty unlikely...
>> >
>> > It seems that it happens when you ask the supplicant to "disconnect" via
>> > the CLI.
>> >
>> at least in my setup issuing a "disconnect" via the CLI ends only with
>> a deauth (as the respective code in wpa_supplicant/ctrl_iface.c seems
>> to call only wpa_supplicant_deauthenticate())
>
> Hm. Maybe it was removing the interface then, or something. I don't
> remember, but Ilan said he had a way to trigger this.
>
> In any case, it seems we should handle it in some way?
>
well, it sounds rare enough to me.
maybe we can/should just drop it in this case (if there is no channel
context attached)?

Eliad.

2012-08-24 09:29:49

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 00/20] mac80211: multi-channel work

On Fri, 2012-07-27 at 13:16 +0200, Johannes Berg wrote:

> Comments welcome!

Ilan pointed me to a problem here yesterday.

Say we authenticate, then at that time we'll bind the virtual interface
into an appropriate channel context. Now we associate, and keep that
channel context. So far, so good.

Now say we disassociate. At this point, the connection is gone, so we
remove the channel context.

Now if the supplicant wants to deauthenticate as well, we have no
channel context to use for it. We could use remain-on-channel? Or we
could create a new channel context? Or just ignore the deauth? I haven't
found a good solution yet... We also can't rely on the supplicant always
doing a deauth, so we don't want to keep the channel context around
until the deauth either.

Obviously the same can also happen if the supplicant just asks us to
deauthenticate without ever having connected at all, but that's a rather
unlikely case.

Anyone have any idea? :)

johannes


2012-08-26 08:10:28

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 00/20] mac80211: multi-channel work

On Sun, 2012-08-26 at 10:58 +0300, Eliad Peller wrote:

> > Now if the supplicant wants to deauthenticate as well, we have no
> > channel context to use for it. We could use remain-on-channel? Or we
> > could create a new channel context? Or just ignore the deauth? I haven't
> > found a good solution yet... We also can't rely on the supplicant always
> > doing a deauth, so we don't want to keep the channel context around
> > until the deauth either.
> >
> > Obviously the same can also happen if the supplicant just asks us to
> > deauthenticate without ever having connected at all, but that's a rather
> > unlikely case.
> >
> > Anyone have any idea? :)
> >
> is it really different from the situation today, when we'll try tx on
> idle device/interface (afaict)?

Well, it is still a bit different, we have no channel at all :)

> this scenario (deauth after disassoc) also sounds pretty unlikely...

It seems that it happens when you ask the supplicant to "disconnect" via
the CLI.

johannes


2012-08-26 08:28:46

by Eliad Peller

[permalink] [raw]
Subject: Re: [RFC 00/20] mac80211: multi-channel work

On Sun, Aug 26, 2012 at 11:10 AM, Johannes Berg
<[email protected]> wrote:
> On Sun, 2012-08-26 at 10:58 +0300, Eliad Peller wrote:
>
>> > Now if the supplicant wants to deauthenticate as well, we have no
>> > channel context to use for it. We could use remain-on-channel? Or we
>> > could create a new channel context? Or just ignore the deauth? I haven't
>> > found a good solution yet... We also can't rely on the supplicant always
>> > doing a deauth, so we don't want to keep the channel context around
>> > until the deauth either.
>> >
>> > Obviously the same can also happen if the supplicant just asks us to
>> > deauthenticate without ever having connected at all, but that's a rather
>> > unlikely case.
>> >
>> > Anyone have any idea? :)
>> >
>> is it really different from the situation today, when we'll try tx on
>> idle device/interface (afaict)?
>
> Well, it is still a bit different, we have no channel at all :)
>
right, but when the device is idle you are not expected to be tuned to
any channel as well, so it's pretty similar :)

>> this scenario (deauth after disassoc) also sounds pretty unlikely...
>
> It seems that it happens when you ask the supplicant to "disconnect" via
> the CLI.
>
at least in my setup issuing a "disconnect" via the CLI ends only with
a deauth (as the respective code in wpa_supplicant/ctrl_iface.c seems
to call only wpa_supplicant_deauthenticate())

Eliad.

2012-08-06 15:22:16

by Arik Nemtsov

[permalink] [raw]
Subject: Re: [RFC 20/20] mac80211: use channel contexts

On Fri, Jul 27, 2012 at 2:16 PM, Johannes Berg
<[email protected]> wrote:
> From: Johannes Berg <[email protected]>
>
> Instead of operating on a single channel only,
> use the new channel context infrastructure in
> all mac80211 code.
>
> This enables drivers that want to use the new
> channel context infrastructure to use multiple
> channels, while nothing should change for all
> the other drivers that don't support it.
>
> Signed-off-by: Johannes Berg <[email protected]>
[...]
> static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
> struct ieee80211_channel *chan,
> enum nl80211_channel_type channel_type)
> {
> - return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
> + return 0;
> +//return ieee80211_set_channel(wiphy, NULL, chan, channel_type);

typo?

[...]
> @@ -1278,11 +1271,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
> if (type == ieee80211_vif_type_p2p(&sdata->vif))
> return 0;
>
> - /* Setting ad-hoc mode on non-IBSS channel is not supported. */
> - if (sdata->local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS &&
> - type == NL80211_IFTYPE_ADHOC)
> - return -EOPNOTSUPP;
> -
> if (ieee80211_sdata_running(sdata)) {
> ret = ieee80211_runtime_change_iftype(sdata, type);
> if (ret)
> @@ -1294,9 +1282,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
> }
>
> /* reset some values that shouldn't be kept across type changes */
> - sdata->vif.bss_conf.basic_rates =
> - ieee80211_mandatory_rates(sdata->local,
> - sdata->local->oper_channel->band);

was this a bug? shouldn't be updated to use the channel context?

Arik

2012-08-26 07:58:27

by Eliad Peller

[permalink] [raw]
Subject: Re: [RFC 00/20] mac80211: multi-channel work

On Fri, Aug 24, 2012 at 12:29 PM, Johannes Berg
<[email protected]> wrote:
> On Fri, 2012-07-27 at 13:16 +0200, Johannes Berg wrote:
>
>> Comments welcome!
>
> Ilan pointed me to a problem here yesterday.
>
> Say we authenticate, then at that time we'll bind the virtual interface
> into an appropriate channel context. Now we associate, and keep that
> channel context. So far, so good.
>
> Now say we disassociate. At this point, the connection is gone, so we
> remove the channel context.
>
> Now if the supplicant wants to deauthenticate as well, we have no
> channel context to use for it. We could use remain-on-channel? Or we
> could create a new channel context? Or just ignore the deauth? I haven't
> found a good solution yet... We also can't rely on the supplicant always
> doing a deauth, so we don't want to keep the channel context around
> until the deauth either.
>
> Obviously the same can also happen if the supplicant just asks us to
> deauthenticate without ever having connected at all, but that's a rather
> unlikely case.
>
> Anyone have any idea? :)
>
is it really different from the situation today, when we'll try tx on
idle device/interface (afaict)?
this scenario (deauth after disassoc) also sounds pretty unlikely...

Eliad.

2012-08-06 15:26:11

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 20/20] mac80211: use channel contexts

On Mon, 2012-08-06 at 18:21 +0300, Arik Nemtsov wrote:

> > static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
> > struct ieee80211_channel *chan,
> > enum nl80211_channel_type channel_type)
> > {
> > - return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
> > + return 0;
> > +//return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
>
> typo?
>
> [...]

More "todo", but this was indeed missing. I have addressed it in my new
versions in the mac80211-next/wip branch.

> > @@ -1278,11 +1271,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
> > if (type == ieee80211_vif_type_p2p(&sdata->vif))
> > return 0;
> >
> > - /* Setting ad-hoc mode on non-IBSS channel is not supported. */
> > - if (sdata->local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS &&
> > - type == NL80211_IFTYPE_ADHOC)
> > - return -EOPNOTSUPP;
> > -
> > if (ieee80211_sdata_running(sdata)) {
> > ret = ieee80211_runtime_change_iftype(sdata, type);
> > if (ret)
> > @@ -1294,9 +1282,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
> > }
> >
> > /* reset some values that shouldn't be kept across type changes */
> > - sdata->vif.bss_conf.basic_rates =
> > - ieee80211_mandatory_rates(sdata->local,
> > - sdata->local->oper_channel->band);
>
> was this a bug? shouldn't be updated to use the channel context?

Well, the first was a leftover from before we even had an explicit IBSS
join operation -- now the (default) channel is just checked when you try
to join an IBSS, so the code in the first hunk has truly been
unnecessary for quite a while.

The second hunk ... similar story, it should be set whenever we first
use the interface by starting AP, joining IBSS or connecting to an AP or
mesh or whatever else could happen. So I think it should be safe.

johannes


2012-08-26 08:30:39

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 00/20] mac80211: multi-channel work

On Sun, 2012-08-26 at 11:28 +0300, Eliad Peller wrote:

> >> this scenario (deauth after disassoc) also sounds pretty unlikely...
> >
> > It seems that it happens when you ask the supplicant to "disconnect" via
> > the CLI.
> >
> at least in my setup issuing a "disconnect" via the CLI ends only with
> a deauth (as the respective code in wpa_supplicant/ctrl_iface.c seems
> to call only wpa_supplicant_deauthenticate())

Hm. Maybe it was removing the interface then, or something. I don't
remember, but Ilan said he had a way to trigger this.

In any case, it seems we should handle it in some way?

johannes


2012-09-05 14:02:44

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 00/20] mac80211: multi-channel work

On Sun, 2012-08-26 at 11:36 +0300, Eliad Peller wrote:
> On Sun, Aug 26, 2012 at 11:30 AM, Johannes Berg
> <[email protected]> wrote:
> > On Sun, 2012-08-26 at 11:28 +0300, Eliad Peller wrote:
> >
> >> >> this scenario (deauth after disassoc) also sounds pretty unlikely...
> >> >
> >> > It seems that it happens when you ask the supplicant to "disconnect" via
> >> > the CLI.
> >> >
> >> at least in my setup issuing a "disconnect" via the CLI ends only with
> >> a deauth (as the respective code in wpa_supplicant/ctrl_iface.c seems
> >> to call only wpa_supplicant_deauthenticate())
> >
> > Hm. Maybe it was removing the interface then, or something. I don't
> > remember, but Ilan said he had a way to trigger this.
> >
> > In any case, it seems we should handle it in some way?
> >
> well, it sounds rare enough to me.
> maybe we can/should just drop it in this case (if there is no channel
> context attached)?

Maybe, yes. I just asked Jouni and he said he was moving towards *just*
deauth, will probably do it at least for now.

johannes