Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: pull-request: iwlwifi-fixes 2013-06-14
From: Emmanuel Grumbach @ 2013-06-15 19:33 UTC (permalink / raw)
  To: John W. Linville; +Cc: Johannes Berg, linux-wireless, Stanislaw Gruszka
In-Reply-To: <20130614173419.GB28497@tuxdriver.com>

>> I have two more fixes that I think would be worthwhile for 3.10 but
>> admittedly the scenario is somewhat unlikely, so if you want to hold
>> them for 3.11 I can live with that. In that case, I can put them into my
>> -next tree, or you can pull this into -next (but if you don't pull
>> wireless.git first you'd get some more fixes you already have.)
>>
>> These two patches fix two issues with using rfkill randomly during
>> traffic, which would then cause our driver to stop working and not be
>> able to recover at all.
>>
>> johannes
>>
>>
>
> It isn't obvious to me that these need to be included in 3.10.  I can
> pull this into wireless-next once the current stuff in wireless makes
> it to davem's tree.
>
> If you decide that these really need to go, please provide some more
> information on how likely users are to hit the bugs, or how serious
> the effects of that would be.
>

John, it is really your call. I understand these concerns in -rc5.
For the first patch, I am not 100% sure that it fixes anything else
that a print. It is obvious to me that without this patch, you might
get an error in the log (I reproduced it a few times). I tend to say
that the print is harmless though.
The second patch fixes a real issue. The issue is hard to reproduce
though. You need to get in a case where the queues are full (sw queues
are stopped) and at that precise time, you need to free the Tx queues
(RFkill - because any other flow would flush the queues first I
think). If you got into that situation, then the queues would remain
stopped after you switch the RFkill button again. So yes... Unlikely.

I would still recommend distros (Stanislaw is CCed) to take both
patches since they are really safe and can avoid issues.

Now you have all the data :-)

^ permalink raw reply

* Re: kmemleak report in 3.9.5+, related to cfg80211_inform_bss_frame
From: Ben Greear @ 2013-06-15 19:18 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <1371316275.8319.0.camel@jlt4.sipsolutions.net>

On 06/15/2013 10:11 AM, Johannes Berg wrote:
> On Fri, 2013-06-14 at 15:48 -0700, Ben Greear wrote:
>
>> I've instrumented all (as far as I can tell) allocation points
>> and destruction points for the ies, and I am keeping a separate
>> list of structures to record some info about each ies.
>>
>> I loaded up lots of stations, let them bounce around for a while,
>> and then did an 'rmmod ath9k'.
>>
>> I still see 14 ies entries in my debug list.  Should
>> I expect to see zero ies data structures left after
>> I rmmod all wifi drivers, or is it normal for a few
>> to be left around?
>
> No, that's decidedly not normal, but that's pretty much just what
> kmemleak already told us, no? Good to verify, but doesn't really help
> pinpoint the problem either, I'd say :-(

Well, I wanted to make sure it wasn't false-positive in kmemleak.

Sometime around March someone reported a similar issue but decided
kmemleak was wrong (and you fixed one corner case that was reported
at the same time)..

I tried instrumenting the bss as well.  From what I can tell, we are
leaking them, as when I print out all bss for the phy* objects, I only
get 14.  But, I see several hundred that were allocated and never freed.

kmemleak didn't show leaked bss, so possibly I am wrong about this, or
maybe they are still (properly?) referenced from the virtual station
interfaces.

Is there any good reason that there would be a significant amount of bss
objects in the system that are not in the bss_list for the wiphys?

This is from my debug code, but perhaps it gives an idea (actually,
the ies are undercounted, as 31500 was the buffer size I
allowed for debugfs...I'll work on better instrumentation to
give an accurate count of still-allocated ies.)

[root@LEC2220-1 ~]# cat /debug/ieee80211/wiphy*/bss|wc
      14     112    1288
[root@LEC2220-1 ~]# cat /debug/ieee80211/ies |wc
     642    1286   31500
[root@LEC2220-1 ~]# cat /debug/ieee80211/all_bss|wc
     382     764   16044


The good news is that it appears the bss growth (at least) does not grow too fast..this
is after around 20 hours of running the torture test that constantly is trying to
(re)associate 400 stations with an AP that can handle only 127.

Thanks,
Ben


>
> johannes
>


-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


^ permalink raw reply

* Re: kmemleak report in 3.9.5+, related to cfg80211_inform_bss_frame
From: Johannes Berg @ 2013-06-15 17:11 UTC (permalink / raw)
  To: Ben Greear; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <51BB9DC5.2020509@candelatech.com>

On Fri, 2013-06-14 at 15:48 -0700, Ben Greear wrote:

> I've instrumented all (as far as I can tell) allocation points
> and destruction points for the ies, and I am keeping a separate
> list of structures to record some info about each ies.
> 
> I loaded up lots of stations, let them bounce around for a while,
> and then did an 'rmmod ath9k'.
> 
> I still see 14 ies entries in my debug list.  Should
> I expect to see zero ies data structures left after
> I rmmod all wifi drivers, or is it normal for a few
> to be left around?

No, that's decidedly not normal, but that's pretty much just what
kmemleak already told us, no? Good to verify, but doesn't really help
pinpoint the problem either, I'd say :-(

johannes


^ permalink raw reply

* Re: unable to force transmission rate on injection
From: Oleksij Rempel @ 2013-06-15  7:24 UTC (permalink / raw)
  To: George Nychis; +Cc: linux-wireless@vger.kernel.org, ath9k_htc_fw
In-Reply-To: <CA+7oygcTxgPiVbup6BT-+sJWFNy=nMTc8C7OeCew9Xc6WgQinw@mail.gmail.com>

Hi George,

ath9k_htc use internal rate controller which is located insight of 
firmware. If you have time, i'll suggest to take it in your hands.

Am 15.06.2013 01:58, schrieb George Nychis:
> I have an ath9k_htc card that I am trying to force a transmission rate
> on injection.  I did some digging around and found this patch from
> Pavel:
>
> http://article.gmane.org/gmane.linux.kernel.wireless.general/47441
>
> I updated and implemented that patch in to my kernel, and I see my
> injected packets coming down through the code.  I see that the rates I
> am trying to transmit pass the test to make sure that the rate is
> available:
>
> [ 1244.647325] *** gnychis: OK on rate 540 -- idx: 11
> [ 1244.682061] *** gnychis: OK on rate 480 -- idx: 10
> [ 1244.741305] *** gnychis: OK on rate 360 -- idx: 9
> ...
>
> And then I double checked to make sure that, given the flag,
> ieee80211_tx_h_rate_ctrl() is *not* being called.  So, to the best of
> my knowledge the patch supplied seems to keeping the supplied rate and
> disabling rate control.
>
> But, for some reason it still keeps getting transmitted at a rate of
> 1Mbps.  I have verified this with an independent receiver.  If I do a
> pcapdump on the transmitting interface, I see two packets for every
> transmission.  One at the rate I am trying to transmit at, and another
> at 1Mbps:
> http://users.ece.cmu.edu/~gnychis/bad_tx.pcap
>
> Am I missing something else in mac80211 to inject at a specific rate?
>
> Thanks!
> George
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


-- 
Regards,
Oleksij

^ permalink raw reply

* RE: [PATCH] mwifiex: fix memory corruption when unsetting multicast list
From: Bing Zhao @ 2013-06-15  4:08 UTC (permalink / raw)
  To: Daniel Drake, linville@tuxdriver.com; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <20130614192424.9463CFAAC8@dev.laptop.org>

Hi Daniel,

Thanks for the patch.

> When trying to unset a previously-set multicast list (i.e. the new list
> has 0 entries), mwifiex_set_multicast_list() was calling down to
> mwifiex_request_set_multicast_list() while leaving
> mcast_list.num_multicast_addr as an uninitialized value.
> 
> We were arriving at mwifiex_cmd_mac_multicast_adr() which would then
> proceed to do an often huge memcpy of
> mcast_list.num_multicast_addr*ETH_ALEN bytes, causing memory corruption
> and hard to debug crashes.
> 
> Fix this by setting mcast_list.num_multicast_addr to 0 when no multicast
> list is provided. Similarly, fix up the logic in
> mwifiex_request_set_multicast_list() to unset the multicast list that
> was previously sent to the hardware in such cases.
> 
> Signed-off-by: Daniel Drake <dsd@laptop.org>

Acked-by: Bing Zhao <bzhao@marvell.com>

Thanks,
Bing

> ---
>  drivers/net/wireless/mwifiex/main.c      |  5 ++---
>  drivers/net/wireless/mwifiex/sta_ioctl.c | 18 ++++++++----------
>  2 files changed, 10 insertions(+), 13 deletions(-)


^ permalink raw reply

* unable to force transmission rate on injection
From: George Nychis @ 2013-06-14 23:58 UTC (permalink / raw)
  To: linux-wireless@vger.kernel.org

I have an ath9k_htc card that I am trying to force a transmission rate
on injection.  I did some digging around and found this patch from
Pavel:

http://article.gmane.org/gmane.linux.kernel.wireless.general/47441

I updated and implemented that patch in to my kernel, and I see my
injected packets coming down through the code.  I see that the rates I
am trying to transmit pass the test to make sure that the rate is
available:

[ 1244.647325] *** gnychis: OK on rate 540 -- idx: 11
[ 1244.682061] *** gnychis: OK on rate 480 -- idx: 10
[ 1244.741305] *** gnychis: OK on rate 360 -- idx: 9
...

And then I double checked to make sure that, given the flag,
ieee80211_tx_h_rate_ctrl() is *not* being called.  So, to the best of
my knowledge the patch supplied seems to keeping the supplied rate and
disabling rate control.

But, for some reason it still keeps getting transmitted at a rate of
1Mbps.  I have verified this with an independent receiver.  If I do a
pcapdump on the transmitting interface, I see two packets for every
transmission.  One at the rate I am trying to transmit at, and another
at 1Mbps:
http://users.ece.cmu.edu/~gnychis/bad_tx.pcap

Am I missing something else in mac80211 to inject at a specific rate?

Thanks!
George

^ permalink raw reply

* Re: Double 'put' of bss in mac80211/mlme.c?
From: Ben Greear @ 2013-06-14 23:38 UTC (permalink / raw)
  To: linux-wireless@vger.kernel.org
In-Reply-To: <51BBA888.7030309@candelatech.com>

On 06/14/2013 04:34 PM, Ben Greear wrote:
> Looks like an easy way to leak ies would be to mess up the
> ref counting on bss objects.
>
> While looking at such code, I found this in mac80211/mlme.c
>
> The destroy_assoc_data does a put_bss, and then it is put again
> directly.  Is this on purpose, or would this effectively cause
> a double-free?
>
>          if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {
>              /* oops -- internal error -- send timeout for now */
>              ieee80211_destroy_assoc_data(sdata, false);
>              cfg80211_put_bss(sdata->local->hw.wiphy, *bss);
>              return RX_MGMT_CFG80211_ASSOC_TIMEOUT;
>          }
>
> Thanks,
> Ben
>

Gah, nevermind...one is assoc_data->bss, the other is auth_data->bss.

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


^ permalink raw reply

* Double 'put' of bss in mac80211/mlme.c?
From: Ben Greear @ 2013-06-14 23:34 UTC (permalink / raw)
  To: linux-wireless@vger.kernel.org

Looks like an easy way to leak ies would be to mess up the
ref counting on bss objects.

While looking at such code, I found this in mac80211/mlme.c

The destroy_assoc_data does a put_bss, and then it is put again
directly.  Is this on purpose, or would this effectively cause
a double-free?

		if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {
			/* oops -- internal error -- send timeout for now */
			ieee80211_destroy_assoc_data(sdata, false);
			cfg80211_put_bss(sdata->local->hw.wiphy, *bss);
			return RX_MGMT_CFG80211_ASSOC_TIMEOUT;
		}

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


^ permalink raw reply

* Re: kmemleak report in 3.9.5+, related to cfg80211_inform_bss_frame
From: Ben Greear @ 2013-06-14 22:48 UTC (permalink / raw)
  To: linux-wireless@vger.kernel.org
In-Reply-To: <51B7C29C.1060701@candelatech.com>

On 06/11/2013 05:36 PM, Ben Greear wrote:
> On 06/11/2013 12:08 PM, Ben Greear wrote:
>> On 06/11/2013 12:00 PM, Ben Greear wrote:
>>> I see several reports similar to the one below while doing some
>>> kmemleak testing on my 3.9.5+ tree (with local patches applied):
>>>
>>> http://dmz2.candelatech.com/git/gitweb.cgi?p=linux-3.9.dev.y/.git;a=summary
>
>>> The kmemleak report is below:
>>>
>>>
>>> unreferenced object 0xffff8801c8e41e78 (size 192):
>>>    comm "kworker/u:2", pid 157, jiffies 4295509873 (age 86582.869s)
>>>    hex dump (first 32 bytes):
>>>      41 0d 00 30 02 00 00 00 6b 6b 6b 6b 6b 6b 6b 6b  A..0....kkkkkkkk
>>>      6b 6b 6b 6b 6b 6b 6b 6b 69 00 00 00 00 0c 2e 32  kkkkkkkki......2
>>>    backtrace:
>>>      [<ffffffff815de7bf>] kmemleak_alloc+0x73/0x98
>>>      [<ffffffff8118b4d4>] slab_post_alloc_hook+0x28/0x2a
>>>      [<ffffffff8118d605>] __kmalloc+0xf9/0x122
>>>      [<ffffffffa027cb27>] cfg80211_inform_bss_frame+0x114/0x1f8 [cfg80211]
>>>      [<ffffffffa03d6865>] ieee80211_bss_info_update+0x66/0x21f [mac80211]
>>>      [<ffffffffa040aec6>] ieee80211_rx_bss_info+0x12f/0x1ca [mac80211]
>>>      [<ffffffffa040b017>] ieee80211_rx_mgmt_probe_resp+0xb6/0x197 [mac80211]
>>>      [<ffffffffa040e8a3>] ieee80211_sta_rx_queued_mgmt+0xdd/0x60e [mac80211]
>>>      [<ffffffffa03df0ee>] ieee80211_iface_work+0x238/0x2cc [mac80211]
>>>      [<ffffffff810b0cd3>] process_one_work+0x292/0x42e
>>>      [<ffffffff810b36af>] worker_thread+0x14f/0x264
>>>      [<ffffffff810b7bea>] kthread+0xc7/0xcf
>>>      [<ffffffff815f64ec>] ret_from_fork+0x7c/0xb0
>>>      [<ffffffffffffffff>] 0xffffffffffffffff

I am still working on trying to figure this one out.

I've instrumented all (as far as I can tell) allocation points
and destruction points for the ies, and I am keeping a separate
list of structures to record some info about each ies.

I loaded up lots of stations, let them bounce around for a while,
and then did an 'rmmod ath9k'.

I still see 14 ies entries in my debug list.  Should
I expect to see zero ies data structures left after
I rmmod all wifi drivers, or is it normal for a few
to be left around?


Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


^ permalink raw reply

* Re: [PATCH 1/2] iw: Allow user to provide freq during mesh join
From: Ashok Nagarajan @ 2013-06-14 21:39 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, John Linville, devel, Javier Cardona
In-Reply-To: <1370953615.8356.34.camel@jlt4.sipsolutions.net>

On Tue, Jun 11, 2013 at 5:26 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Mon, 2013-06-03 at 10:34 -0700, Ashok Nagarajan wrote:
>> Allow user to configure frequency and channel type during mesh join command.
>>
>> Signed-off-by: Ashok Nagarajan <ashok@cozybit.com>
>> ---
>>  mesh.c |   49 ++++++++++++++++++++++++++++++++++++++++++++++---
>>  1 files changed, 46 insertions(+), 3 deletions(-)
>>
>> diff --git a/mesh.c b/mesh.c
>> index 5a09b62..ec202c9 100644
>> --- a/mesh.c
>> +++ b/mesh.c
>> @@ -431,8 +431,18 @@ static int join_mesh(struct nl80211_state *state, struct nl_cb *cb,
>>  {
>>       struct nlattr *container;
>>       float rate;
>> -     int bintval, dtim_period;
>> +     int bintval, dtim_period, i;
>>       char *end;
>> +     static const struct {
>> +             const char *name;
>> +             unsigned int val;
>> +     } htmap[] = {
>> +             { .name = "HT20", .val = NL80211_CHAN_HT20, },
>> +             { .name = "HT40+", .val = NL80211_CHAN_HT40PLUS, },
>> +             { .name = "HT40-", .val = NL80211_CHAN_HT40MINUS, },
>> +             { .name = "NOHT", .val = NL80211_CHAN_NO_HT, },
>> +     };
>
> I think you should use chandefs already, to allow for VHT. Also, it'd be
> good to refactor the channel parsing for this, monitor and IBSS (though
> I wonder why I haven't done that already?)
>

Sure. That makes sense. I will get that in the next version.

Thanks,
Ashok
> johannes
>



--
Ashok Raj Nagarajan,
cozybit Inc.
http://www.cozybit.com

^ permalink raw reply

* Re: [PATCH v2] {nl,mac,cfg}80211: Allow user to configure basic rates for mesh
From: Ashok Nagarajan @ 2013-06-14 21:38 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, John Linville, devel, Javier Cardona
In-Reply-To: <1370953555.8356.33.camel@jlt4.sipsolutions.net>

Hi Johannes,

On Tue, Jun 11, 2013 at 5:25 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Mon, 2013-06-03 at 10:33 -0700, Ashok Nagarajan wrote:
>> Currently mesh uses mandatory rates as the default basic rates. Allow basic
>> rates to be configured during mesh join. Basic rates are applied only if
>> channel is also provided with mesh join command.
>
> Applied, I fixed some whitespace and made it remove rates specification
> w/o channel specification. Please check.
>

I checked it. Thank you.

> johannes
>



--
Ashok Raj Nagarajan,
cozybit Inc.
http://www.cozybit.com

^ permalink raw reply

* [PATCH] mwifiex: fix memory corruption when unsetting multicast list
From: Daniel Drake @ 2013-06-14 19:24 UTC (permalink / raw)
  To: linville, bzhao; +Cc: linux-wireless

When trying to unset a previously-set multicast list (i.e. the new list
has 0 entries), mwifiex_set_multicast_list() was calling down to
mwifiex_request_set_multicast_list() while leaving
mcast_list.num_multicast_addr as an uninitialized value.

We were arriving at mwifiex_cmd_mac_multicast_adr() which would then
proceed to do an often huge memcpy of
mcast_list.num_multicast_addr*ETH_ALEN bytes, causing memory corruption
and hard to debug crashes.

Fix this by setting mcast_list.num_multicast_addr to 0 when no multicast
list is provided. Similarly, fix up the logic in
mwifiex_request_set_multicast_list() to unset the multicast list that
was previously sent to the hardware in such cases.

Signed-off-by: Daniel Drake <dsd@laptop.org>
---
 drivers/net/wireless/mwifiex/main.c      |  5 ++---
 drivers/net/wireless/mwifiex/sta_ioctl.c | 18 ++++++++----------
 2 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 2eb88ea..4f5c37a 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -573,9 +573,8 @@ static void mwifiex_set_multicast_list(struct net_device *dev)
 		mcast_list.mode = MWIFIEX_ALL_MULTI_MODE;
 	} else {
 		mcast_list.mode = MWIFIEX_MULTICAST_MODE;
-		if (netdev_mc_count(dev))
-			mcast_list.num_multicast_addr =
-				mwifiex_copy_mcast_addr(&mcast_list, dev);
+		mcast_list.num_multicast_addr =
+			mwifiex_copy_mcast_addr(&mcast_list, dev);
 	}
 	mwifiex_request_set_multicast_list(priv, &mcast_list);
 }
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 1a8a19d..23aa910 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -104,16 +104,14 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
 		} else {
 			priv->curr_pkt_filter &=
 				~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
-			if (mcast_list->num_multicast_addr) {
-				dev_dbg(priv->adapter->dev,
-					"info: Set multicast list=%d\n",
-				       mcast_list->num_multicast_addr);
-				/* Send multicast addresses to firmware */
-				ret = mwifiex_send_cmd_async(priv,
-					HostCmd_CMD_MAC_MULTICAST_ADR,
-					HostCmd_ACT_GEN_SET, 0,
-					mcast_list);
-			}
+			dev_dbg(priv->adapter->dev,
+				"info: Set multicast list=%d\n",
+				mcast_list->num_multicast_addr);
+			/* Send multicast addresses to firmware */
+			ret = mwifiex_send_cmd_async(priv,
+				HostCmd_CMD_MAC_MULTICAST_ADR,
+				HostCmd_ACT_GEN_SET, 0,
+				mcast_list);
 		}
 	}
 	dev_dbg(priv->adapter->dev,
-- 
1.8.1.4


^ permalink raw reply related

* equivalent of AR_DIAG_FORCE_RX_CLEAR on rt2x00?
From: George Nychis @ 2013-06-14 18:38 UTC (permalink / raw)
  To: linux-wireless@vger.kernel.org

Hi all,

I have carrier sense (both physical and virtual) disabled on an
ath9k_htc card using AR_DIAG_FORCE_RX_CLEAR and
AR_DIAG_IGNORE_VIRT_CS.   I was hoping to do the same thing with the
rt2x00.

I scoured through rt2800.h but didn't see any relevant registers.  It
also seems like the rt2x00 datasheets are private.  The only thing I
can find is access to CWmin/CWmax, which might be able to give me
similar behavior (but, probably not if it behaves like the Atheros
cards).  RX_BUSY seems to only be relevant for counting channel busy
time?

If anyone knows of anything, I'd appreciate it!

Thanks,
George

^ permalink raw reply

* Re: where is ath9k debugfs?
From: George Nychis @ 2013-06-14 18:21 UTC (permalink / raw)
  To: Pat Erley; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <51B7A9FB.9020706@erley.org>

Hi Pat,

You're correct on this.  I always seem to forget about the distinction
between ath9k and ath_htc.  Thanks a bunch!

- George

On Tue, Jun 11, 2013 at 6:51 PM, Pat Erley <pat-lkml@erley.org> wrote:
> On 06/11/2013 12:40 PM, George Nychis wrote:
>>
>> I have configured my kernel to use ath9k debugfs:
>> $ grep ATH9K_DEBUGFS /boot/config-`uname -r`
>> CONFIG_ATH9K_DEBUGFS=y
>>
>> The location of these debugfs files should be in
>> /sys/kernel/debug/ath9k according to:
>>
>> http://wireless.kernel.org/en/users/Drivers/ath9k/debug#Debugfs_files_for_ath9k
>>
>> However, when I load the modules and plug in an ath9k device, I do not
>> get any ath9k debugfs files:
>> root@parallels:/sys# find /sys -name ath9k
>> root@parallels:/sys# find /sys -name rx_chainmask
>> root@parallels:/sys# find /sys -name disable_ani
>> root@parallels:/sys#
>>
>> I do get the ieee80211 debug, though:
>> # ls -l /sys/kernel/debug/ieee80211/
>> total 0
>> drwxr-xr-x 6 root root 0 Jun 11 12:30 phy0
>>
>> Do I need to pass some parameter to the kernel module on load to get
>> the ath9k debugfs?  Am I missing something else?
>>
>> Thanks!
>> George
>
>
> Hi George,
>
> When you say 'plug in an ath9k device' I assume you mean you plug it in
> before you boot?  There aren't any ath9k devices that I know of that use
> USB.  I believe they're all handled by ath9k_htc.
>
> Aside from that, you found the right spot (/sys/kernel/debug/ieee80211/phyN)
> for it to live.  What does dmesg say when you plug in/boot with the device?
>
> Pat

^ permalink raw reply

* Re: [GIT] [3.11] NFC updates
From: John W. Linville @ 2013-06-14 17:35 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: Linux Wireless, Linux NFC
In-Reply-To: <20130614115038.GI7998@zurbaran>

On Fri, Jun 14, 2013 at 01:50:38PM +0200, Samuel Ortiz wrote:
> Hi John,
> 
> This is the NFC pull request for 3.11. See below for all the details,
> thanks in advance for pulling them in.
> 
> The following changes since commit b70727e8a61a8e6b4d818519b03fce2937d0ef40:
> 
>   Merge branch 'for-linville-ath10k' of git://github.com/kvalo/ath6kl (2013-06-13 13:54:21 -0400)
> 
> are available in the git repository at:
> 
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-next.git tags/nfc-next-3.11-1
> 
> for you to fetch changes up to bda7eb27635c4d7414fb05a5f55501b71f436cc0:
> 
>   NFC: mei_phy: Clean up file (2013-06-14 13:45:11 +0200)

Pulling now...

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: pull-request: iwlwifi-next 2013-06-14
From: John W. Linville @ 2013-06-14 17:32 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1371206930.8278.8.camel@jlt4.sipsolutions.net>

On Fri, Jun 14, 2013 at 12:48:50PM +0200, Johannes Berg wrote:
> John,
> 
> Here are some more things for -next. I will have another pull request
> some time next week because we're preparing to release the firmware for
> the 7000 series devices, and unfortunately that will require an API
> bump.
> 
> This time I have a number of cleanups, a small fix from Emmanuel and two
> performance improvements that combined reduce our driver's CPU
> utilisation as much as 75% in high TX-throughput scenarios.
> 
> johannes
> 
> 
> The following changes since commit 8eb3871076875f247483f4a1fe6713e6d440c53e:
> 
>   iwlwifi: mvm: Update the supported interface combinations (2013-06-11 20:17:06 +0200)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git for-john
> 
> for you to fetch changes up to adaf69186c24100d34c2fb107dacd33546cad3c5:
> 
>   iwlwifi: mvm: remove obsolete comment (2013-06-13 16:43:16 +0200)

Pulling now...

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: pull-request: iwlwifi-fixes 2013-06-14
From: John W. Linville @ 2013-06-14 17:34 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1371206567.8278.3.camel@jlt4.sipsolutions.net>

On Fri, Jun 14, 2013 at 12:42:47PM +0200, Johannes Berg wrote:
> John,
> 
> I have two more fixes that I think would be worthwhile for 3.10 but
> admittedly the scenario is somewhat unlikely, so if you want to hold
> them for 3.11 I can live with that. In that case, I can put them into my
> -next tree, or you can pull this into -next (but if you don't pull
> wireless.git first you'd get some more fixes you already have.)
> 
> These two patches fix two issues with using rfkill randomly during
> traffic, which would then cause our driver to stop working and not be
> able to recover at all.
> 
> johannes
> 
> 
> The following changes since commit 622ebe994f6866b8d46ee5d3bcc329ed65d3722d:
> 
>   iwlwifi: fix rate control regression (2013-06-12 14:13:39 +0200)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-fixes.git for-john
> 
> for you to fetch changes up to 8a487b1a7432b20ff3f82387a8ce7555a964b44e:
> 
>   iwlwifi: pcie: wake the queue if stopped when being unmapped (2013-06-13 16:44:04 +0200)
> 
> ----------------------------------------------------------------
> Emmanuel Grumbach (2):
>       iwlwifi: pcie: fix race in queue unmapping
>       iwlwifi: pcie: wake the queue if stopped when being unmapped
> 
>  drivers/net/wireless/iwlwifi/pcie/tx.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)

It isn't obvious to me that these need to be included in 3.10.  I can
pull this into wireless-next once the current stuff in wireless makes
it to davem's tree.

If you decide that these really need to go, please provide some more
information on how likely users are to hit the bugs, or how serious
the effects of that would be.

John
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: Power saving features for iwl4965
From: Stanislaw Gruszka @ 2013-06-14 13:18 UTC (permalink / raw)
  To: Pedro Francisco; +Cc: Tino Keitel, ML linux-wireless
In-Reply-To: <CAJZjf_zOF=qGEE=pWDRe0YDpAYophm93cVM8pfuL0sTRGq56EA@mail.gmail.com>

On Fri, Jun 14, 2013 at 01:50:58PM +0100, Pedro Francisco wrote:
> >> >> Could you try this experimental patch? (...)
> >> >
> >> > I am trying the iwlegacy powersave patch along with CPU scheduler BFS
> >> > and IO scheduler BFQ.
> >> >
> >> > I've got this today: (...)
> >> >
> >> > (...)
> >> I also got a SYSASSERT:
> >> (...)
> >>
> >> I disabled powersave (but kept running the same kernel) and none of
> >> the errors appeared again.
> >
> > Yes, this seems to be iwlegacy PS issue and has to be fixed before
> > this patch could be applied.
> 
> But is it a driver-only issue? I had assumed it was some sort of
> fireware+driver issue...
Looks like driver issue or firmware issue that can be workaround in 
the driver.

> Will running with debug on help? Or is it easily reproducible on any
> iwl3945 / iwl4465 ?
> 
> Because in my case (iwl3945) it happens after boot, no prior suspend
> to RAM is required to trigger the issues.
I can reproduce microcode error on iwl4965 by reloading modules. Looks
like we put device in sleep mode and it can not be properly booted when
driver initalize. I did not yet test patch on iwl3945. When I'll do
this, I think I'll be able to reproduce problems you discovered. If not
I'll ask for more debug info.

Thanks
Stanislaw

^ permalink raw reply

* Re: Power saving features for iwl4965
From: Pedro Francisco @ 2013-06-14 12:50 UTC (permalink / raw)
  To: Stanislaw Gruszka; +Cc: Tino Keitel, ML linux-wireless
In-Reply-To: <20130611161924.GB1696@redhat.com>

On Tue, Jun 11, 2013 at 5:19 PM, Stanislaw Gruszka <sgruszka@redhat.com> wrote:
> On Mon, Jun 10, 2013 at 08:31:33PM +0100, Pedro Francisco wrote:
>> On Sun, Jun 9, 2013 at 1:28 AM, Pedro Francisco
>> <pedrogfrancisco@gmail.com> wrote:
>> > On Mon, Jun 3, 2013 at 3:18 PM, Stanislaw Gruszka <sgruszka@redhat.com> wrote:
>> >> On Mon, Jun 03, 2013 at 10:52:39AM +0200, Tino Keitel wrote:
>> >>> (...)
>> >>> It would be really nice to have proper power management in a current
>> >>> kernel, as the laptop gets noticeably hotter with the current iwlegacy
>> >>> driver.  That's why I still use a 3.1.10 kernel with an old
>> >>> forward-ported iwlagn driver.
>> >>
>> >> Could you try this experimental patch? (...)
>> >
>> > I am trying the iwlegacy powersave patch along with CPU scheduler BFS
>> > and IO scheduler BFQ.
>> >
>> > I've got this today: (...)
>> >
>> > (...)
>> I also got a SYSASSERT:
>> (...)
>>
>> I disabled powersave (but kept running the same kernel) and none of
>> the errors appeared again.
>
> Yes, this seems to be iwlegacy PS issue and has to be fixed before
> this patch could be applied.

But is it a driver-only issue? I had assumed it was some sort of
fireware+driver issue...

Will running with debug on help? Or is it easily reproducible on any
iwl3945 / iwl4465 ?

Because in my case (iwl3945) it happens after boot, no prior suspend
to RAM is required to trigger the issues.

P.S.: the demise of bugzilla.intellinuxwireless.org it's very
difficult to find useful info about this. It would appear 4465 is just
affected after suspend, believing the patch which disabled PS in 2009.

^ permalink raw reply

* [PATCHv2 5/5] ath9k: enable CSA functionality in ath9k
From: Simon Wunderlich @ 2013-06-14 12:15 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Simon Wunderlich, Mathias Kretschmer
In-Reply-To: <1371212124-26264-1-git-send-email-siwu@hrz.tu-chemnitz.de>

CSA is only enabled for one interface, but the same limitation applies
for mac80211 too. It checks whether the beacon has been sent (different
approaches for non-EDMA-enabled and EDMA-enabled devices), and completes
the channel switch after that.

Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
Changes to PATCHv1:
 * complete channel switch after the last beacon has been sent
---
 drivers/net/wireless/ath/ath9k/ath9k.h  |    2 ++
 drivers/net/wireless/ath/ath9k/beacon.c |   21 +++++++++++++++++++++
 drivers/net/wireless/ath/ath9k/main.c   |   17 +++++++++++++++++
 drivers/net/wireless/ath/ath9k/xmit.c   |    2 ++
 4 files changed, 42 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 579ed9c..3745487 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -424,6 +424,7 @@ void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
 void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
 void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif);
 void ath9k_set_beacon(struct ath_softc *sc);
+bool ath9k_csa_is_finished(struct ath_softc *sc);
 
 /*******************/
 /* Link Monitoring */
@@ -751,6 +752,7 @@ struct ath_softc {
 #endif
 
 	struct ath_descdma txsdma;
+	struct ieee80211_vif *csa_vif;
 
 	struct ath_ant_comb ant_comb;
 	u8 ant_tx, ant_rx;
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index fd1eeba..e400151 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -310,6 +310,23 @@ void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif)
 		(unsigned long long)tsfadjust, avp->av_bslot);
 }
 
+bool ath9k_csa_is_finished(struct ath_softc *sc)
+{
+	struct ieee80211_vif *vif;
+
+	vif = sc->csa_vif;
+	if (!vif || !vif->csa_active)
+		return false;
+
+	if (!ieee80211_csa_is_complete(vif))
+		return false;
+
+	ieee80211_csa_finish(vif);
+	vif->csa_active = 0;
+	sc->csa_vif = NULL;
+	return true;
+}
+
 void ath9k_beacon_tasklet(unsigned long data)
 {
 	struct ath_softc *sc = (struct ath_softc *)data;
@@ -355,6 +372,10 @@ void ath9k_beacon_tasklet(unsigned long data)
 		return;
 	}
 
+	/* EDMA devices check that in the tx completion function. */
+	if (!edma && ath9k_csa_is_finished(sc))
+		return;
+
 	slot = ath9k_beacon_choose_slot(sc);
 	vif = sc->beacon.bslot[slot];
 
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index cc5a98b..57d0642 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1026,6 +1026,9 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
 	if (ath9k_uses_beacons(vif->type))
 		ath9k_beacon_remove_slot(sc, vif);
 
+	if (sc->csa_vif == vif)
+		sc->csa_vif = NULL;
+
 	ath9k_ps_wakeup(sc);
 	ath9k_calculate_summary_state(hw, NULL);
 	ath9k_ps_restore(sc);
@@ -2319,6 +2322,19 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
 	clear_bit(SC_OP_SCANNING, &sc->sc_flags);
 }
 
+static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw,
+					struct ieee80211_vif *vif)
+{
+	struct ath_softc *sc = hw->priv;
+
+	/* mac80211 does not support CSA in multi-if cases (yet) */
+	if (WARN_ON(sc->csa_vif))
+		return;
+
+	vif->csa_active = 1;
+	sc->csa_vif = vif;
+}
+
 struct ieee80211_ops ath9k_ops = {
 	.tx 		    = ath9k_tx,
 	.start 		    = ath9k_start,
@@ -2366,4 +2382,5 @@ struct ieee80211_ops ath9k_ops = {
 #endif
 	.sw_scan_start	    = ath9k_sw_scan_start,
 	.sw_scan_complete   = ath9k_sw_scan_complete,
+	.channel_switch_beacon     = ath9k_channel_switch_beacon,
 };
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index eab0fcb..cec670d 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -2282,6 +2282,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
 		if (ts.qid == sc->beacon.beaconq) {
 			sc->beacon.tx_processed = true;
 			sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
+
+			ath9k_csa_is_finished(sc);
 			continue;
 		}
 
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv2 4/5] mac80211: add channel switch command and beacon callbacks
From: Simon Wunderlich @ 2013-06-14 12:15 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Simon Wunderlich, Mathias Kretschmer
In-Reply-To: <1371212124-26264-1-git-send-email-siwu@hrz.tu-chemnitz.de>

The count field in CSA must be decremented with each beacon
transmitted. This patch implements the functionality for drivers
using ieee80211_beacon_get(). Other drivers must call back manually
after reaching count == 0.

This patch also contains the handling and finish worker for the channel
switch command.

Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
Changes to PATCHv1:
 * don't switch when CAC is active
 * add hw to parameters for driver

Changes to RFCv1:
 * use beacons as supplied from nl80211 without generating/parsing them
 * update beacons using offsets
 * report back by calling the channel switch event in cfg80211
---
 include/net/mac80211.h     |   33 ++++++++++++++
 net/mac80211/cfg.c         |  109 +++++++++++++++++++++++++++++++++++++++++++-
 net/mac80211/driver-ops.h  |   11 +++++
 net/mac80211/ieee80211_i.h |   11 +++++
 net/mac80211/iface.c       |    2 +
 net/mac80211/trace.h       |   20 ++++++++
 net/mac80211/tx.c          |   68 +++++++++++++++++++++++++++
 7 files changed, 252 insertions(+), 2 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index a405a7a..f0592cd 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1078,6 +1078,7 @@ enum ieee80211_vif_flags {
  * @addr: address of this interface
  * @p2p: indicates whether this AP or STA interface is a p2p
  *	interface, i.e. a GO or p2p-sta respectively
+ * @csa_active: marks whether a channel switch is going on
  * @driver_flags: flags/capabilities the driver has for this interface,
  *	these need to be set (or cleared) when the interface is added
  *	or, if supported by the driver, the interface type is changed
@@ -1100,6 +1101,7 @@ struct ieee80211_vif {
 	struct ieee80211_bss_conf bss_conf;
 	u8 addr[ETH_ALEN];
 	bool p2p;
+	bool csa_active;
 
 	u8 cab_queue;
 	u8 hw_queue[IEEE80211_NUM_ACS];
@@ -2631,6 +2633,16 @@ enum ieee80211_roc_type {
  * @ipv6_addr_change: IPv6 address assignment on the given interface changed.
  *	Currently, this is only called for managed or P2P client interfaces.
  *	This callback is optional; it must not sleep.
+ *
+ * @channel_switch_beacon: Starts a channel switch for the to a new channel.
+ *	Beacons are modified to include CSA or ECSA IEs before calling this
+ *	function. The corresponding count fields in these IEs must be
+ *	decremented, and when they reach zero the driver must call
+ *	ieee80211_csa_finish(). Drivers which use ieee80211_beacon_get()
+ *	get the csa counter decremented by mac80211, but must check if it is
+ *	zero using ieee80211_csa_is_complete() and then call
+ *	ieee80211_csa_finish().
+ *
  */
 struct ieee80211_ops {
 	void (*tx)(struct ieee80211_hw *hw,
@@ -2818,6 +2830,8 @@ struct ieee80211_ops {
 				 struct ieee80211_vif *vif,
 				 struct inet6_dev *idev);
 #endif
+	void (*channel_switch_beacon)(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif);
 };
 
 /**
@@ -3313,6 +3327,25 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 }
 
 /**
+ * ieee80211_csa_finish - notify mac80211 about channel switch
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * After a channel switch announcement was scheduled and the counter in this
+ * announcement hit zero, this function must be called by the driver to
+ * notify mac80211 that the channel can be changed.
+ */
+void ieee80211_csa_finish(struct ieee80211_vif *vif);
+
+/**
+ * ieee80211_csa_is_complete - find out if counters reached zero
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * This function checks the registered beacon if the counters reached zero.
+ */
+int ieee80211_csa_is_complete(struct ieee80211_vif *vif);
+
+
+/**
  * ieee80211_proberesp_get - retrieve a Probe Response template
  * @hw: pointer obtained from ieee80211_alloc_hw().
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 5ffc7d9..e468465 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -854,8 +854,8 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
 	return 0;
 }
 
-static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
-				   struct cfg80211_beacon_data *params)
+int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
+			    struct cfg80211_beacon_data *params)
 {
 	struct beacon_data *new, *old;
 	int new_head_len, new_tail_len;
@@ -2854,6 +2854,110 @@ error:
 	return NULL;
 }
 
+void ieee80211_csa_finalize_work(struct work_struct *work)
+{
+	struct ieee80211_sub_if_data *sdata =
+		container_of(work, struct ieee80211_sub_if_data,
+			     csa_finalize_work);
+	struct ieee80211_local *local = sdata->local;
+	int err;
+
+	if (!ieee80211_sdata_running(sdata))
+		return;
+
+	if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
+		return;
+
+	netif_carrier_off(sdata->dev);
+	err = ieee80211_vif_use_channel(sdata, &local->csa_chandef,
+					IEEE80211_CHANCTX_SHARED);
+	netif_carrier_on(sdata->dev);
+	if (WARN_ON(err < 0))
+		return;
+	netif_carrier_on(sdata->dev);
+
+	err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
+	cfg80211_beacon_free(sdata->u.ap.next_beacon);
+	sdata->u.ap.next_beacon = NULL;
+
+	ieee80211_wake_queues_by_reason(&sdata->local->hw,
+					IEEE80211_MAX_QUEUE_MAP,
+					IEEE80211_QUEUE_STOP_REASON_CSA);
+
+	ieee80211_bss_info_change_notify(sdata, err);
+
+	cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef);
+}
+
+static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+				    struct cfg80211_csa_settings *params)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_chanctx_conf *chanctx_conf;
+	struct ieee80211_chanctx *chanctx;
+	int err;
+
+	if (!list_empty(&local->roc_list) || local->scanning)
+		return -EBUSY;
+
+	if (sdata->wdev.cac_started)
+		return -EBUSY;
+
+	/* don't handle if chanctx is used */
+	if (local->use_chanctx)
+		return -EBUSY;
+
+	rcu_read_lock();
+	mutex_lock(&local->chanctx_mtx);
+	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+	if (!chanctx_conf) {
+		mutex_unlock(&local->chanctx_mtx);
+		rcu_read_unlock();
+		return -EBUSY;
+	}
+
+	/* don't handle for multi-VIF cases */
+	chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
+	if (chanctx->refcount > 1) {
+		mutex_unlock(&local->chanctx_mtx);
+		rcu_read_unlock();
+		return -EBUSY;
+	}
+	mutex_unlock(&local->chanctx_mtx);
+	rcu_read_unlock();
+
+	/* only handle AP for now. */
+	switch (sdata->vif.type) {
+	case NL80211_IFTYPE_AP:
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	sdata->csa_counter_offset_beacon = params->counter_offset_beacon;
+	sdata->csa_counter_offset_presp = params->counter_offset_presp;
+	sdata->u.ap.next_beacon = cfg80211_beacon_dup(&params->beacon_after);
+	if (!sdata->u.ap.next_beacon)
+		return -ENOMEM;
+
+	if (params->block_tx)
+		ieee80211_stop_queues_by_reason(&local->hw,
+				IEEE80211_MAX_QUEUE_MAP,
+				IEEE80211_QUEUE_STOP_REASON_CSA);
+
+	err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
+	if (err < 0)
+		return err;
+
+	local->csa_chandef = params->chandef;
+
+	ieee80211_bss_info_change_notify(sdata, err);
+	drv_channel_switch_beacon(sdata);
+
+	return 0;
+}
+
 static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 			     struct ieee80211_channel *chan, bool offchan,
 			     unsigned int wait, const u8 *buf, size_t len,
@@ -3581,4 +3685,5 @@ struct cfg80211_ops mac80211_config_ops = {
 	.get_et_strings = ieee80211_get_et_strings,
 	.get_channel = ieee80211_cfg_get_channel,
 	.start_radar_detection = ieee80211_start_radar_detection,
+	.channel_switch = ieee80211_channel_switch,
 };
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index b931c96..a8952f6 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1072,4 +1072,15 @@ static inline void drv_ipv6_addr_change(struct ieee80211_local *local,
 }
 #endif
 
+static inline void
+drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	if (local->ops->channel_switch_beacon) {
+		trace_drv_channel_switch_beacon(sdata);
+		local->ops->channel_switch_beacon(&local->hw, &sdata->vif);
+	}
+}
+
+
 #endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 7a6f1a0..d34d816 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -258,6 +258,8 @@ struct ieee80211_if_ap {
 	struct beacon_data __rcu *beacon;
 	struct probe_resp __rcu *probe_resp;
 
+	/* to be used after channel switch. */
+	struct cfg80211_beacon_data *next_beacon;
 	struct list_head vlans;
 
 	struct ps_data ps;
@@ -713,6 +715,10 @@ struct ieee80211_sub_if_data {
 
 	struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
 
+	struct work_struct csa_finalize_work;
+	int csa_counter_offset_beacon;
+	int csa_counter_offset_presp;
+
 	/* used to reconfigure hardware SM PS */
 	struct work_struct recalc_smps;
 
@@ -1340,6 +1346,8 @@ void ieee80211_roc_purge(struct ieee80211_local *local,
 void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free);
 void ieee80211_sw_roc_work(struct work_struct *work);
 void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
+/* channel switch handling */
+void ieee80211_csa_finalize_work(struct work_struct *work);
 
 /* interface handling */
 int ieee80211_iface_init(void);
@@ -1362,6 +1370,9 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local);
 
 bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
 void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
+int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
+			    struct cfg80211_beacon_data *params);
+
 
 static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
 {
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 7cabaf2..d17692d 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -800,6 +800,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
 	cancel_work_sync(&local->dynamic_ps_enable_work);
 
 	cancel_work_sync(&sdata->recalc_smps);
+	cancel_work_sync(&sdata->csa_finalize_work);
 
 	cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
 
@@ -1263,6 +1264,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 	skb_queue_head_init(&sdata->skb_queue);
 	INIT_WORK(&sdata->work, ieee80211_iface_work);
 	INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
+	INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
 
 	switch (type) {
 	case NL80211_IFTYPE_P2P_GO:
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index c215fafd7..6b2af54 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -1906,6 +1906,26 @@ TRACE_EVENT(api_radar_detected,
 	)
 );
 
+TRACE_EVENT(drv_channel_switch_beacon,
+	TP_PROTO(struct ieee80211_sub_if_data *sdata),
+
+	TP_ARGS(sdata),
+
+	TP_STRUCT__entry(
+		VIF_ENTRY
+	),
+
+	TP_fast_assign(
+		VIF_ASSIGN;
+	),
+
+	TP_printk(
+		VIF_PR_FMT " channel switch",
+		VIF_PR_ARG
+	)
+);
+
+
 #ifdef CONFIG_MAC80211_MESSAGE_TRACING
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM mac80211_msg
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 4105d0c..97751e4 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2320,6 +2320,71 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
 	return 0;
 }
 
+void ieee80211_csa_finish(struct ieee80211_vif *vif)
+{
+	struct ieee80211_sub_if_data *sdata = NULL;
+	sdata = vif_to_sdata(vif);
+
+	vif->csa_active = 0;
+	ieee80211_queue_work(&sdata->local->hw,
+			     &sdata->csa_finalize_work);
+}
+EXPORT_SYMBOL(ieee80211_csa_finish);
+
+static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
+				 struct beacon_data *beacon)
+{
+	struct probe_resp *resp;
+	int counter_beacon = sdata->csa_counter_offset_beacon;
+	int counter_presp = sdata->csa_counter_offset_presp;
+
+	if (WARN_ON(counter_beacon > beacon->tail_len))
+		return;
+
+	if (WARN_ON(((u8 *)beacon->tail)[counter_beacon] == 0))
+		return;
+
+	((u8 *)beacon->tail)[counter_beacon]--;
+
+	if (counter_presp && sdata->vif.type == NL80211_IFTYPE_AP) {
+		resp = rcu_dereference(sdata->u.ap.probe_resp);
+		if (WARN_ON(!resp))
+			return;
+		if (WARN_ON(counter_presp > resp->len))
+			return;
+
+		((u8 *)resp->data)[counter_presp]--;
+	}
+}
+
+int ieee80211_csa_is_complete(struct ieee80211_vif *vif)
+{
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+	struct beacon_data *beacon = NULL;
+	int counter_beacon = sdata->csa_counter_offset_beacon;
+
+	if (!sdata || !ieee80211_sdata_running(sdata))
+		return 0;
+
+	if (vif->type == NL80211_IFTYPE_AP) {
+		struct ieee80211_if_ap *ap = &sdata->u.ap;
+		beacon = rcu_dereference(ap->beacon);
+
+	} else {
+		WARN_ON(1);
+		return 0;
+	}
+
+	if (WARN_ON(counter_beacon > beacon->tail_len))
+		return 0;
+
+	if (((u8 *)beacon->tail)[counter_beacon] == 0)
+		return 1;
+
+	return 0;
+}
+EXPORT_SYMBOL(ieee80211_csa_is_complete);
+
 struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 					 struct ieee80211_vif *vif,
 					 u16 *tim_offset, u16 *tim_length)
@@ -2350,6 +2415,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 		struct beacon_data *beacon = rcu_dereference(ap->beacon);
 
 		if (beacon) {
+			if (sdata->vif.csa_active)
+				ieee80211_update_csa(sdata, beacon);
+
 			/*
 			 * headroom, head length,
 			 * tail length and maximum TIM length
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv2 3/5] mac80211: add functions to duplicate a cfg80211_beacon
From: Simon Wunderlich @ 2013-06-14 12:15 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Simon Wunderlich, Mathias Kretschmer
In-Reply-To: <1371212124-26264-1-git-send-email-siwu@hrz.tu-chemnitz.de>

For the channel switch announcement, it is required to set a new beacon
after the driver arrived on the new channel. The new beacon will be set
by nl80211, but is required to duplicate the beacon as the original
memory within the netlink message will be gone. Add functions to
duplicate and free these cfg80211 beacons.

Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
 net/mac80211/cfg.c |   76 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 64cf294..5ffc7d9 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2778,6 +2778,82 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
 	return 0;
 }
 
+static void cfg80211_beacon_free(struct cfg80211_beacon_data *beacon)
+{
+	kfree(beacon->head);
+	kfree(beacon->tail);
+	kfree(beacon->beacon_ies);
+	kfree(beacon->proberesp_ies);
+	kfree(beacon->assocresp_ies);
+	kfree(beacon->probe_resp);
+	kfree(beacon);
+}
+
+static struct cfg80211_beacon_data *
+cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon)
+{
+	struct cfg80211_beacon_data *new_beacon;
+	new_beacon = kzalloc(sizeof(*new_beacon), GFP_KERNEL);
+	if (!beacon)
+		return NULL;
+
+	if (beacon->head_len) {
+		new_beacon->head = kmalloc(beacon->head_len, GFP_KERNEL);
+		new_beacon->head_len = beacon->head_len;
+		if (!new_beacon->head)
+			goto error;
+		memcpy((u8 *)new_beacon->head, beacon->head, beacon->head_len);
+	}
+	if (beacon->tail_len) {
+		new_beacon->tail = kmalloc(beacon->tail_len, GFP_KERNEL);
+		new_beacon->tail_len = beacon->tail_len;
+		if (!new_beacon->tail)
+			goto error;
+		memcpy((u8 *)new_beacon->tail, beacon->tail, beacon->tail_len);
+	}
+	if (beacon->beacon_ies_len) {
+		new_beacon->beacon_ies = kmalloc(beacon->beacon_ies_len,
+						 GFP_KERNEL);
+		new_beacon->beacon_ies_len = beacon->beacon_ies_len;
+		if (!new_beacon->beacon_ies)
+			goto error;
+		memcpy((u8 *)new_beacon->beacon_ies, beacon->beacon_ies,
+		       beacon->beacon_ies_len);
+	}
+	if (beacon->proberesp_ies_len) {
+		new_beacon->proberesp_ies = kmalloc(beacon->proberesp_ies_len,
+						    GFP_KERNEL);
+		new_beacon->proberesp_ies_len = beacon->proberesp_ies_len;
+		if (!new_beacon->proberesp_ies)
+			goto error;
+		memcpy((u8 *)new_beacon->proberesp_ies, beacon->proberesp_ies,
+		       beacon->proberesp_ies_len);
+	}
+	if (beacon->assocresp_ies_len) {
+		new_beacon->assocresp_ies = kmalloc(beacon->assocresp_ies_len,
+						    GFP_KERNEL);
+		new_beacon->assocresp_ies_len = beacon->assocresp_ies_len;
+		if (!new_beacon->assocresp_ies)
+			goto error;
+		memcpy((u8 *)new_beacon->assocresp_ies, beacon->assocresp_ies,
+		       beacon->assocresp_ies_len);
+	}
+	if (beacon->probe_resp_len) {
+		new_beacon->probe_resp = kmalloc(beacon->probe_resp_len,
+						 GFP_KERNEL);
+		new_beacon->probe_resp_len = beacon->probe_resp_len;
+		if (!new_beacon->probe_resp)
+			goto error;
+		memcpy((u8 *)new_beacon->probe_resp, beacon->probe_resp,
+		       beacon->probe_resp_len);
+	}
+
+	return new_beacon;
+error:
+	cfg80211_beacon_free(new_beacon);
+	return NULL;
+}
+
 static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 			     struct ieee80211_channel *chan, bool offchan,
 			     unsigned int wait, const u8 *buf, size_t len,
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv2 1/5] nl80211: use attributes to parse beacons
From: Simon Wunderlich @ 2013-06-14 12:15 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Simon Wunderlich, Mathias Kretschmer
In-Reply-To: <1371212124-26264-1-git-send-email-siwu@hrz.tu-chemnitz.de>

only the attributes are required and not the whole netlink info, as the
function accesses the attributes only anyway. This makes it easier to
parse nested beacon IEs later.

Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
 net/wireless/nl80211.c |   53 +++++++++++++++++++++++-------------------------
 1 file changed, 25 insertions(+), 28 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e402819..1c4f7da 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2882,61 +2882,58 @@ static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
 	return err;
 }
 
-static int nl80211_parse_beacon(struct genl_info *info,
+static int nl80211_parse_beacon(struct nlattr *attrs[],
 				struct cfg80211_beacon_data *bcn)
 {
 	bool haveinfo = false;
 
-	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) ||
-	    !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) ||
-	    !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
-	    !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]))
+	if (!is_valid_ie_attr(attrs[NL80211_ATTR_BEACON_TAIL]) ||
+	    !is_valid_ie_attr(attrs[NL80211_ATTR_IE]) ||
+	    !is_valid_ie_attr(attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
+	    !is_valid_ie_attr(attrs[NL80211_ATTR_IE_ASSOC_RESP]))
 		return -EINVAL;
 
 	memset(bcn, 0, sizeof(*bcn));
 
-	if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
-		bcn->head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
-		bcn->head_len = nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+	if (attrs[NL80211_ATTR_BEACON_HEAD]) {
+		bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]);
+		bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]);
 		if (!bcn->head_len)
 			return -EINVAL;
 		haveinfo = true;
 	}
 
-	if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
-		bcn->tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
-		bcn->tail_len =
-		    nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
+	if (attrs[NL80211_ATTR_BEACON_TAIL]) {
+		bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]);
+		bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]);
 		haveinfo = true;
 	}
 
 	if (!haveinfo)
 		return -EINVAL;
 
-	if (info->attrs[NL80211_ATTR_IE]) {
-		bcn->beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
-		bcn->beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+	if (attrs[NL80211_ATTR_IE]) {
+		bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]);
+		bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]);
 	}
 
-	if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) {
+	if (attrs[NL80211_ATTR_IE_PROBE_RESP]) {
 		bcn->proberesp_ies =
-			nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
+			nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]);
 		bcn->proberesp_ies_len =
-			nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
+			nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]);
 	}
 
-	if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
+	if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
 		bcn->assocresp_ies =
-			nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
+			nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
 		bcn->assocresp_ies_len =
-			nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
+			nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
 	}
 
-	if (info->attrs[NL80211_ATTR_PROBE_RESP]) {
-		bcn->probe_resp =
-			nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]);
-		bcn->probe_resp_len =
-			nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]);
+	if (attrs[NL80211_ATTR_PROBE_RESP]) {
+		bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]);
+		bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]);
 	}
 
 	return 0;
@@ -3015,7 +3012,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 	    !info->attrs[NL80211_ATTR_BEACON_HEAD])
 		return -EINVAL;
 
-	err = nl80211_parse_beacon(info, &params.beacon);
+	err = nl80211_parse_beacon(info->attrs, &params.beacon);
 	if (err)
 		return err;
 
@@ -3167,7 +3164,7 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
 	if (!wdev->beacon_interval)
 		return -EINVAL;
 
-	err = nl80211_parse_beacon(info, &params);
+	err = nl80211_parse_beacon(info->attrs, &params);
 	if (err)
 		return err;
 
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv2 2/5] nl80211/cfg80211: add channel switch command
From: Simon Wunderlich @ 2013-06-14 12:15 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Simon Wunderlich, Mathias Kretschmer
In-Reply-To: <1371212124-26264-1-git-send-email-siwu@hrz.tu-chemnitz.de>

To allow channel switch announcements within beacons, add
the channel switch command to nl80211/cfg80211. This is
implementation is intended for AP and (later) IBSS mode.

Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
Changes to RFCv1:
 * accept and pass CSA IEs and after-change IEs
 * use parameter structure instead of individual parameters
---
 include/net/cfg80211.h       |   26 ++++++++++
 include/uapi/linux/nl80211.h |   29 +++++++++++
 net/wireless/nl80211.c       |  118 +++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 172 insertions(+), 1 deletion(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 3c3a563..0de5384 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -610,6 +610,29 @@ struct cfg80211_ap_settings {
 	bool radar_required;
 };
 
+/* struct cfg80211_csa_settings - channel switch settings
+ *
+ * Used for channel switch
+ *
+ * @chandef: defines the channel to use after the switch
+ * @beacon_csa: beacon data while performing the switch
+ * @counter_offset_beacon: offset for the counter within the beacon (tail)
+ * @counter_offset_presp: offset for the counter within the probe response
+ * @beacon_after: beacon data to be used on the new channel
+ * @radar_required: whether radar detection is required on the new channel
+ * @block_tx: whether transmissions should be blocked while changing
+ * @count: number of beacons until switch
+ */
+struct cfg80211_csa_settings {
+	struct cfg80211_chan_def chandef;
+	struct cfg80211_beacon_data beacon_csa;
+	u16 counter_offset_beacon, counter_offset_presp;
+	struct cfg80211_beacon_data beacon_after;
+	bool radar_required;
+	bool block_tx;
+	u8 count;
+};
+
 /**
  * enum station_parameters_apply_mask - station parameter values to apply
  * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp)
@@ -2278,6 +2301,9 @@ struct cfg80211_ops {
 				    u16 duration);
 	void	(*crit_proto_stop)(struct wiphy *wiphy,
 				   struct wireless_dev *wdev);
+	int	(*channel_switch)(struct wiphy *wiphy,
+				  struct net_device *dev,
+				  struct cfg80211_csa_settings *params);
 };
 
 /*
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index ca6facf..ddf3b9e 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -648,6 +648,16 @@
  * @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can
  *	return back to normal.
  *
+ * @NL80211_CMD_CHANNEL_SWITCH: Perform a channel switch by announcing the
+ *	the new channel information (Channel Switch Announcement - CSA)
+ *	in the beacon for some time (as defined in the
+ *	%NL80211_ATTR_CH_SWITCH_COUNT parameter) and then change to the
+ *	new channel. Userspace provides the new channel information (using
+ *	%NL80211_ATTR_WIPHY_FREQ and the attributes determining channel
+ *	width). %NL80211_ATTR_CH_SWITCH_BLOCK_TX may be supplied to inform
+ *	other station that transmission must be blocked until the channel
+ *	switch is complete.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -810,6 +820,7 @@ enum nl80211_commands {
 	NL80211_CMD_CRIT_PROTOCOL_START,
 	NL80211_CMD_CRIT_PROTOCOL_STOP,
 
+	NL80211_CMD_CHANNEL_SWITCH,
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -1436,6 +1447,18 @@ enum nl80211_commands {
  *	allowed to be used with the first @NL80211_CMD_SET_STATION command to
  *	update a TDLS peer STA entry.
  *
+ * @NL80211_ATTR_CH_SWITCH_COUNT: u32 attribute specifying the number of TBTT's
+ *	until the channel switch event.
+ * @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission
+ *	must be blocked on the current channel (before the channel switch
+ *	operation).
+ * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information
+ *	for the time while performing a channel switch.
+ * @NL80211_ATTR_CSA_C_OFF_BEACON: Offset of the channel switch counter
+ *	field in the beacons tail (%NL80211_ATTR_BEACON_TAIL).
+ * @NL80211_ATTR_CSA_C_OFF_PRESP: Offset of the channel switch counter
+ *	field in the probe response (%NL80211_ATTR_PROBE_RESP).
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1736,6 +1759,12 @@ enum nl80211_attrs {
 
 	NL80211_ATTR_PEER_AID,
 
+	NL80211_ATTR_CH_SWITCH_COUNT,
+	NL80211_ATTR_CH_SWITCH_BLOCK_TX,
+	NL80211_ATTR_CSA_IES,
+	NL80211_ATTR_CSA_C_OFF_BEACON,
+	NL80211_ATTR_CSA_C_OFF_PRESP,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1c4f7da..d48a00d 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -349,6 +349,11 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
 	[NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
 				  .len = IEEE80211_MAX_DATA_LEN },
 	[NL80211_ATTR_PEER_AID] = { .type = NLA_U16 },
+	[NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
+	[NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG },
+	[NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
+	[NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_U16 },
+	[NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 },
 };
 
 /* policy for the key attributes */
@@ -5540,6 +5545,109 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
 	return err;
 }
 
+static int nl80211_channel_switch(struct sk_buff *skb,
+				  struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_csa_settings params;
+	struct nlattr *csa_ies[NL80211_ATTR_MAX+1];
+	u8 radar_detect_width = 0;
+	int err;
+
+	if (!rdev->ops->channel_switch)
+		return -EOPNOTSUPP;
+
+	/* may add IBSS support later */
+	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+		return -EOPNOTSUPP;
+
+	memset(&params, 0, sizeof(params));
+
+	if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
+	    !info->attrs[NL80211_ATTR_CH_SWITCH_COUNT])
+		return -EINVAL;
+
+	/* only important for AP, IBSS and mesh create IEs internally */
+	if (!info->attrs[NL80211_ATTR_CSA_IES] ||
+	    !info->attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
+		return -EINVAL;
+
+	/* useless if AP is not running */
+	if (!wdev->beacon_interval)
+		return -EINVAL;
+
+	params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
+
+	err = nl80211_parse_beacon(info->attrs, &params.beacon_after);
+	if (err)
+		return err;
+
+	err = nla_parse_nested(csa_ies, NL80211_ATTR_MAX,
+				   info->attrs[NL80211_ATTR_CSA_IES],
+				   nl80211_policy);
+	if (err)
+		return err;
+
+	err = nl80211_parse_beacon(csa_ies, &params.beacon_csa);
+	if (err)
+		return err;
+
+	params.counter_offset_beacon =
+		nla_get_u16(info->attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
+	if (params.counter_offset_beacon > params.beacon_csa.tail_len)
+		return -EINVAL;
+
+	/* sanity check - counter should be the same this should be the same */
+	if (params.beacon_csa.tail[params.counter_offset_beacon] !=
+	    params.count)
+		return -EINVAL;
+
+	if (info->attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
+		params.counter_offset_presp =
+			nla_get_u16(info->attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
+		if (params.counter_offset_presp >
+		    params.beacon_csa.probe_resp_len)
+			return -EINVAL;
+
+		if (params.beacon_csa.probe_resp[params.counter_offset_presp] !=
+		    params.count)
+			return -EINVAL;
+	}
+
+	err = nl80211_parse_chandef(rdev, info, &params.chandef);
+	if (err)
+		return err;
+
+	if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
+		return -EINVAL;
+
+	err = cfg80211_chandef_dfs_required(wdev->wiphy, &params.chandef);
+	if (err < 0)
+		return err;
+
+	if (err)
+		radar_detect_width = BIT(params.chandef.width);
+	else
+		radar_detect_width = 0;
+
+	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
+					   params.chandef.chan,
+					   CHAN_MODE_SHARED,
+					   radar_detect_width);
+	if (err)
+		return err;
+
+	if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
+		params.block_tx = true;
+
+	err = rdev->ops->channel_switch(&rdev->wiphy, dev, &params);
+
+	return err;
+}
+
 static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
 			    u32 seq, int flags,
 			    struct cfg80211_registered_device *rdev,
@@ -8995,7 +9103,15 @@ static struct genl_ops nl80211_ops[] = {
 		.flags = GENL_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
-	}
+	},
+	{
+		.cmd = NL80211_CMD_CHANNEL_SWITCH,
+		.doit = nl80211_channel_switch,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+		NL80211_FLAG_NEED_RTNL,
+	},
 };
 
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv2 0/5] add master channel switch announcement support
From: Simon Wunderlich @ 2013-06-14 12:15 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Simon Wunderlich

This is a follow up from PATCHv1 last week. This patchset adds generic
channel switch support for AP. This is required for DFS operation
(e.g. Wi-Fi Alliance requires this for 802.11h certification). This will also
be required for IBSS-DFS later.

Changes from PATCHv1:
 * integrate Felix suggestion to perform the channel switch after the beacon send
   has been completed. This required a few minor design changes (i.e. split into
   functions for decrementation and check for csa completion in mac80211)
 * few minor changes (e.g. check for CSA in mac80211, documentation)

The rough design is:
 * userspace asks kernel to switch a channel using the new NL80211_CMD_CHANNEL_SWITCH
   command. It supplies IE information for the time while staying on the old channel and
   announcing the switch, and IE information for after the switch to the new channel. 
 * IE information contains the beacon and optionally probe responses, which should
   include (E)CSA IEs for the CSA case. Furthermore an offset is provided (for beacon
   and probe response) to point to the counter field within the channel switch IEs.
 * The driver gets the new beacons passed and must set them, and decrement the
   counter field. When it reaches 0, the channel is changed and userspace notified.

Discussion points:
 * Assembling all these IE information is a little bit tedious but doable (I've
   patched hostapd).
 * Other future users like IBSS/MESH will not get the beacon/probe response IEs, as they
   generate these beacons themselves. Therefore they need the COUNT attribute, which
   is kind of duplicate right now.
 * Userspace must generate/handle all IEs, which lifts the previous limitations of
   the RFC (e.g. no change of band allowed, no operation mode change allowed).
 * it currently works for me [TM] on my ath9k based machine

As always, any comments are appreciated.

Cheers,
	Simon 

Simon Wunderlich (5):
  nl80211: use attributes to parse beacons
  nl80211/cfg80211: add channel switch command
  mac80211: add functions to duplicate a cfg80211_beacon
  mac80211: add channel switch command and beacon callbacks
  ath9k: enable CSA functionality in ath9k

 drivers/net/wireless/ath/ath9k/ath9k.h  |    2 +
 drivers/net/wireless/ath/ath9k/beacon.c |   21 ++++
 drivers/net/wireless/ath/ath9k/main.c   |   17 +++
 drivers/net/wireless/ath/ath9k/xmit.c   |    2 +
 include/net/cfg80211.h                  |   26 +++++
 include/net/mac80211.h                  |   33 ++++++
 include/uapi/linux/nl80211.h            |   29 +++++
 net/mac80211/cfg.c                      |  185 ++++++++++++++++++++++++++++++-
 net/mac80211/driver-ops.h               |   11 ++
 net/mac80211/ieee80211_i.h              |   11 ++
 net/mac80211/iface.c                    |    2 +
 net/mac80211/trace.h                    |   20 ++++
 net/mac80211/tx.c                       |   68 ++++++++++++
 net/wireless/nl80211.c                  |  171 +++++++++++++++++++++++-----
 14 files changed, 567 insertions(+), 31 deletions(-)

-- 
1.7.10.4


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox