* Re: pull-request: mac80211-next 2013-08-06
From: John W. Linville @ 2013-08-09 19:08 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1375779392.8219.9.camel@jlt4.sipsolutions.net>
On Tue, Aug 06, 2013 at 10:56:32AM +0200, Johannes Berg wrote:
> Hi John,
>
> And one more for mac80211-next (and I have nothing for mac80211 today).
>
> Here I have an IBSS improvement, interworking (11u) definitions, a
> change to make the LED blinking nicer, more VHT (11ac) definitions, VHT
> radiotap TX status, channel switch support in cfg80211 and mac80211 as
> well as a small new debugfs file showing driver-buffered data for
> sleeping clients.
>
> Let me know if there's any problem.
>
> Thanks,
> johannes
>
> The following changes since commit c82b5a74cc739385db6e4275fe504a0e9469bf01:
>
> mac80211: make active monitor injection work w/ HW queue (2013-07-16 09:58:19 +0300)
>
> are available in the git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git for-john
>
> for you to fetch changes up to 73da7d5bab79ad7e16ff44d67c3fe8b9c0b33e5b:
>
> mac80211: add channel switch command and beacon callbacks (2013-08-01 18:30:33 +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-08-06
From: John W. Linville @ 2013-08-09 19:07 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1375779167.8219.5.camel@jlt4.sipsolutions.net>
On Tue, Aug 06, 2013 at 10:52:47AM +0200, Johannes Berg wrote:
> Hi John,
>
> And a few more things for the -next stream for iwlwifi. The signal
> strength reporting fix is the reason I'd originally tried to ask you to
> not pull before :-)
>
> This time I have a signal strength reporting fix from Avri, some
> cleanups from Eliad, Eyal and myself and a new debugfs file from Matti.
>
> Please let me know if there's any problem.
>
> Thanks,
> johannes
>
> The following changes since commit 147fc9be81d10e6e863323c0b54e140b42fd1ed6:
>
> iwlwifi: mvm: advertise support for DYNAMIC / STATIC SMPS (2013-07-31 11:05:08 +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 ef4394b9477f9078d78ae3e8359eae094c9b19d8:
>
> iwlwifi: mvm: use designated initialization for some arrays (2013-08-06 10:35:04 +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: FUSB200 xhci issue
From: Oleksij Rempel @ 2013-08-09 18:53 UTC (permalink / raw)
To: Alan Stern
Cc: Christian Lamparter, Sarah Sharp, Seth Forshee, ath9k_htc_fw,
USB list, linux-wireless
In-Reply-To: <Pine.LNX.4.44L0.1308091310560.1405-100000@iolanthe.rowland.org>
Am 09.08.2013 19:16, schrieb Alan Stern:
> On Fri, 9 Aug 2013, Oleksij Rempel wrote:
>
>> Am 09.08.2013 16:52, schrieb Alan Stern:
>>> On Fri, 9 Aug 2013, Oleksij Rempel wrote:
>>>
>>>>> What about a "get firmware version" sort of thing? There really should
>>>>> be a way for the driver to tell whether the firmware has already been
>>>>> updated.
>>>>
>>>> I was not able to find good direct way to check firmware version. If i
>>>> would add some new command then i will get option like: if responding FW
>>>> is updated; if not, then dead or old.
>>>> How about overwriting iProduct field? Let say, if iProduct == ath9k_htc,
>>>> then firmware is updated? Is it more or less acceptable method? I need
>>>> to ask this because it is really new for me.
>>>
>>> Changing the iProduct string descriptor would work, because the
>>> descriptors_changed() routine doesn't compare the old value of that
>>> string with the new value. (On the other hand, it does compare the
>>> iSerialNumber strings.)
>>
>> Just to make sure. You mean, i should avoid changing iSerialNumber
>> because host will initiate usb reset and this device will probably not
>> survive it?
>
> Right. If the device would survive a reset then there would be no
> problem.
>
> BTW, it is common for new firmware to change the bcdDevice value in the
> device descriptor. That might be easier than changing a string
> descriptor.
>
>>> Is there any way to read the firmware back from the device? Then you
>>> could check directly.
>>
>> No, this device is a SoC with usb client interface based on FUSB200 core
>> (If i'm correct, same core as on carl9170 devices). We can't read memory
>> unless FW provide this service.
>> At power on, this device will boot from external or internal ROM and
>> load minimal FW. Without it, USB wont work.
>> If i read FW code correctly, it should be responsible for suspend and reset.
>
> How do you tell the device to start running the new firmware after it
> is loaded? Normally this requires some sort of reset.
There are two vendor commands cUSB_REQ_DOWNLOAD and
cUSB_REQ_DOWNLOAD_COMP. With cUSB_REQ_DOWNLOAD firmware will be uploaded
and cUSB_REQ_DOWNLOAD_COMP should just jump to first address of the
firmware.
This system has micro modular structure. Firmware can register own
modules. Or relink modules of bootloader, but this is limited only to
existing api.
> Is there any way to prevent the device from losing its firmware during
> a USB reset or suspend?
For suspend - yes. It is possible to ignore suspend command or put the
SoC in low power mode - but is it probably not so easy to bring it back.
I would need to read more code and create some doc as side effect untill
i understand how it works.
I'm not sure how about reset command. I would need more testing and some
ones help. If i see it correctly, usb reset should affect only usb core
and usb pll.
How can i trigger usb reset?
--
Regards,
Oleksij
^ permalink raw reply
* Re: pull-request: iwlwifi-fixes 2013-08-06
From: John W. Linville @ 2013-08-09 17:49 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1375779012.8219.3.camel@jlt4.sipsolutions.net>
On Tue, Aug 06, 2013 at 10:50:12AM +0200, Johannes Berg wrote:
> John,
>
> I have a few more fixes for iwlwifi.
>
> We revert an rfkill bugfix that unfortunately caused more bugs, shuffle
> some code to avoid touching the PCIe device before it's enabled and
> disconnect if firmware fails to do our bidding. I also have Stanislaw's
> fix to not crash in some channel switch scenarios.
>
> Let me know if there's any problem.
>
> Thanks,
> johannes
>
> The following changes since commit a53ee0a308b16e392e0219c585b10f329345766b:
>
> iwlwifi: pcie: clear RFKILL interrupt in AMPG (2013-07-26 10:07:10 +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 057397943eee0bf3bc01a58ee52a9a6f1810258e:
>
> iwlwifi: mvm: disconnect if time event scheduling fails (2013-08-06 10:35:19 +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: [PATCH 2/2] rtlwifi: sparse warnings: cast to restricted type
From: John W. Linville @ 2013-08-09 17:41 UTC (permalink / raw)
To: Larry Finger; +Cc: Mark Schulte, linux-wireless
In-Reply-To: <51F947A9.3050802@lwfinger.net>
On Wed, Jul 31, 2013 at 12:21:45PM -0500, Larry Finger wrote:
> On 07/31/2013 02:08 AM, Mark Schulte wrote:
> >Adding type casts to suppress sparse warnings:
> > * warning: cast to restricted __le32/__le16
> >
> >Signed-off-by: Mark Schulte <schultetwin@gmail.com>
> >---
> > drivers/net/wireless/rtlwifi/ps.c | 16 ++++++++--------
> > 1 file changed, 8 insertions(+), 8 deletions(-)
>
> I think this patch is OK, but until I get a chance to test it on a
> big-endian machine (PowerBook G4 Titanium), please do not apply it.
>
> When I tried the patch, I discovered some kind of regression that
> causes a kernel oops with an RTL8192CU device installed. This patch
> is not the problem, but I will need to bisect the oops before I can
> test. The machine takes a long time to build each kernel, thus it
> will probably be a while.
Any word on this? The patch doesn't look like it should be causing
such problems...?
--
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
* [PATCH v3] brcmsmac: Fix WARNING caused by lack of calls to dma_mapping_error()
From: John W. Linville @ 2013-08-09 17:36 UTC (permalink / raw)
To: linux-wireless
Cc: Larry Finger, Brett Rudley, Arend van Spriel,
Franky (Zhenhui) Lin, Hante Meuleman, brcm80211-dev-list,
John W. Linville, Stable
In-Reply-To: <51E852DE.6000403@broadcom.com>
From: "John W. Linville" <linville@tuxdriver.com>
The driver fails to check the results of DMA mapping in twp places,
which results in the following warning:
[ 28.078515] ------------[ cut here ]------------
[ 28.078529] WARNING: at lib/dma-debug.c:937 check_unmap+0x47e/0x930()
[ 28.078533] bcma-pci-bridge 0000:0e:00.0: DMA-API: device driver failed to check map error[device address=0x00000000b5d60d6c] [size=1876 bytes] [mapped as
single]
[ 28.078536] Modules linked in: bnep bluetooth vboxpci(O) vboxnetadp(O) vboxnetflt(O) vboxdrv(O) ipv6 b43 brcmsmac rtl8192cu rtl8192c_common rtlwifi mac802
11 brcmutil cfg80211 snd_hda_codec_conexant rng_core snd_hda_intel kvm_amd snd_hda_codec ssb kvm mmc_core snd_pcm snd_seq snd_timer snd_seq_device snd k8temp
cordic joydev serio_raw hwmon sr_mod sg pcmcia pcmcia_core soundcore cdrom i2c_nforce2 i2c_core forcedeth bcma snd_page_alloc autofs4 ext4 jbd2 mbcache crc1
6 scsi_dh_alua scsi_dh_hp_sw scsi_dh_rdac scsi_dh_emc scsi_dh ata_generic pata_amd
[ 28.078602] CPU: 1 PID: 2570 Comm: NetworkManager Tainted: G O 3.10.0-rc7-wl+ #42
[ 28.078605] Hardware name: Hewlett-Packard HP Pavilion dv2700 Notebook PC/30D6, BIOS F.27 11/27/2008
[ 28.078607] 0000000000000009 ffff8800bbb03ad8 ffffffff8144f898 ffff8800bbb03b18
[ 28.078612] ffffffff8103e1eb 0000000000000002 ffff8800b719f480 ffff8800b7b9c010
[ 28.078617] ffffffff824204c0 ffffffff81754d57 0000000000000754 ffff8800bbb03b78
[ 28.078622] Call Trace:
[ 28.078624] <IRQ> [<ffffffff8144f898>] dump_stack+0x19/0x1b
[ 28.078634] [<ffffffff8103e1eb>] warn_slowpath_common+0x6b/0xa0
[ 28.078638] [<ffffffff8103e2c1>] warn_slowpath_fmt+0x41/0x50
[ 28.078650] [<ffffffff8122d7ae>] check_unmap+0x47e/0x930
[ 28.078655] [<ffffffff8122de4c>] debug_dma_unmap_page+0x5c/0x70
[ 28.078679] [<ffffffffa04a808c>] dma64_getnextrxp+0x10c/0x190 [brcmsmac]
[ 28.078691] [<ffffffffa04a9042>] dma_rx+0x62/0x240 [brcmsmac]
[ 28.078707] [<ffffffffa0479101>] brcms_c_dpc+0x211/0x9d0 [brcmsmac]
[ 28.078717] [<ffffffffa046d927>] ? brcms_dpc+0x27/0xf0 [brcmsmac]
[ 28.078731] [<ffffffffa046d947>] brcms_dpc+0x47/0xf0 [brcmsmac]
[ 28.078736] [<ffffffff81047dcc>] tasklet_action+0x6c/0xf0
--snip--
[ 28.078974] [<ffffffff813891bd>] SyS_sendmsg+0xd/0x20
[ 28.078979] [<ffffffff81455c24>] tracesys+0xdd/0xe2
[ 28.078982] ---[ end trace 6164d1a08148e9c8 ]---
[ 28.078984] Mapped at:
[ 28.078985] [<ffffffff8122c8fd>] debug_dma_map_page+0x9d/0x150
[ 28.078989] [<ffffffffa04a9322>] dma_rxfill+0x102/0x3d0 [brcmsmac]
[ 28.079001] [<ffffffffa047a13d>] brcms_c_init+0x87d/0x1100 [brcmsmac]
[ 28.079010] [<ffffffffa046d851>] brcms_init+0x21/0x30 [brcmsmac]
[ 28.079018] [<ffffffffa04786e0>] brcms_c_up+0x150/0x430 [brcmsmac]
As the patch adds a new failure mechanism to dma_rxfill(). When I changed the
comment at the start of the routine to add that information, I also polished
the wording.
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Stable <stable@vger.kernel.org>
Cc: Brett Rudley <brudley@broadcom.com>
Cc: Arend van Spriel <arend@broadcom.com>
Cc: Franky (Zhenhui) Lin <frankyl@broadcom.com>
Cc: Hante Meuleman <meuleman@broadcom.com>
Cc: brcm80211-dev-list@broadcom.com
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
Did this one get lost?
V2 - fixed two patch errors.
V3 - address comments from Arend (linville)
drivers/net/wireless/brcm80211/brcmsmac/dma.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c
index 1860c57..4fb9635 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c
@@ -1015,9 +1015,10 @@ static bool dma64_txidle(struct dma_info *di)
/*
* post receive buffers
- * return false is refill failed completely and ring is empty this will stall
- * the rx dma and user might want to call rxfill again asap. This unlikely
- * happens on memory-rich NIC, but often on memory-constrained dongle
+ * Return false if refill failed completely or dma mapping failed. The ring
+ * is empty, which will stall the rx dma and user might want to call rxfill
+ * again asap. This is unlikely to happen on a memory-rich NIC, but often on
+ * memory-constrained dongle.
*/
bool dma_rxfill(struct dma_pub *pub)
{
@@ -1078,6 +1079,8 @@ bool dma_rxfill(struct dma_pub *pub)
pa = dma_map_single(di->dmadev, p->data, di->rxbufsize,
DMA_FROM_DEVICE);
+ if (dma_mapping_error(di->dmadev, pa))
+ return false;
/* save the free packet pointer */
di->rxp[rxout] = p;
@@ -1284,7 +1287,11 @@ static void dma_txenq(struct dma_info *di, struct sk_buff *p)
/* get physical address of buffer start */
pa = dma_map_single(di->dmadev, data, len, DMA_TO_DEVICE);
-
+ /* if mapping failed, free skb */
+ if (dma_mapping_error(di->dmadev, pa)) {
+ brcmu_pkt_buf_free_skb(p);
+ return;
+ }
/* With a DMA segment list, Descriptor table is filled
* using the segment list instead of looping over
* buffers in multi-chain DMA. Therefore, EOF for SGLIST
--
1.8.1.4
^ permalink raw reply related
* Re: FUSB200 xhci issue
From: Alan Stern @ 2013-08-09 17:16 UTC (permalink / raw)
To: Oleksij Rempel
Cc: Christian Lamparter, Sarah Sharp, Seth Forshee, ath9k_htc_fw,
USB list, linux-wireless
In-Reply-To: <52051009.9010001@rempel-privat.de>
On Fri, 9 Aug 2013, Oleksij Rempel wrote:
> Am 09.08.2013 16:52, schrieb Alan Stern:
> > On Fri, 9 Aug 2013, Oleksij Rempel wrote:
> >
> >>> What about a "get firmware version" sort of thing? There really should
> >>> be a way for the driver to tell whether the firmware has already been
> >>> updated.
> >>
> >> I was not able to find good direct way to check firmware version. If i
> >> would add some new command then i will get option like: if responding FW
> >> is updated; if not, then dead or old.
> >> How about overwriting iProduct field? Let say, if iProduct == ath9k_htc,
> >> then firmware is updated? Is it more or less acceptable method? I need
> >> to ask this because it is really new for me.
> >
> > Changing the iProduct string descriptor would work, because the
> > descriptors_changed() routine doesn't compare the old value of that
> > string with the new value. (On the other hand, it does compare the
> > iSerialNumber strings.)
>
> Just to make sure. You mean, i should avoid changing iSerialNumber
> because host will initiate usb reset and this device will probably not
> survive it?
Right. If the device would survive a reset then there would be no
problem.
BTW, it is common for new firmware to change the bcdDevice value in the
device descriptor. That might be easier than changing a string
descriptor.
> > Is there any way to read the firmware back from the device? Then you
> > could check directly.
>
> No, this device is a SoC with usb client interface based on FUSB200 core
> (If i'm correct, same core as on carl9170 devices). We can't read memory
> unless FW provide this service.
> At power on, this device will boot from external or internal ROM and
> load minimal FW. Without it, USB wont work.
> If i read FW code correctly, it should be responsible for suspend and reset.
How do you tell the device to start running the new firmware after it
is loaded? Normally this requires some sort of reset.
Is there any way to prevent the device from losing its firmware during
a USB reset or suspend?
Alan Stern
^ permalink raw reply
* [PATCHv2] mac80211: ibss - do not scan if not needed when creating an IBSS
From: Antonio Quartulli @ 2013-08-09 16:58 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, Antonio Quartulli
In-Reply-To: <1375862917-3625-1-git-send-email-ordex@autistici.org>
From: Antonio Quartulli <antonio@open-mesh.com>
In some cases mac80211 will scan before creating an IBSS
even if bssid and frequency have been forced by the user.
This is not needed and leads only to a delay in the IBSS
establishment phase.
Immediately create the cell if both bssid and frequency
(and fixed_freq is set) have been specified.
Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
net/mac80211/ibss.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index e08387c..79e294e 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -891,6 +891,17 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
return;
}
+ /* if a fixed bssid and a fixed freq have been provided create the IBSS
+ * directly and do not waste time scanning
+ */
+ if (ifibss->fixed_bssid && ifibss->fixed_channel) {
+ sdata_info(sdata, "Created IBSS using preconfigured BSSID %pM\n",
+ bssid);
+ ieee80211_sta_create_ibss(sdata);
+ return;
+ }
+
+
ibss_dbg(sdata, "sta_find_ibss: did not try to join ibss\n");
/* Selected IBSS not found in current scan results - try to scan */
--
1.8.1.5
^ permalink raw reply related
* Re: FUSB200 xhci issue
From: Oleksij Rempel @ 2013-08-09 15:51 UTC (permalink / raw)
To: Alan Stern
Cc: Christian Lamparter, Sarah Sharp, Seth Forshee, ath9k_htc_fw,
USB list, linux-wireless
In-Reply-To: <Pine.LNX.4.44L0.1308091043220.1405-100000@iolanthe.rowland.org>
Am 09.08.2013 16:52, schrieb Alan Stern:
> On Fri, 9 Aug 2013, Oleksij Rempel wrote:
>
>>> What about a "get firmware version" sort of thing? There really should
>>> be a way for the driver to tell whether the firmware has already been
>>> updated.
>>
>> I was not able to find good direct way to check firmware version. If i
>> would add some new command then i will get option like: if responding FW
>> is updated; if not, then dead or old.
>> How about overwriting iProduct field? Let say, if iProduct == ath9k_htc,
>> then firmware is updated? Is it more or less acceptable method? I need
>> to ask this because it is really new for me.
>
> Changing the iProduct string descriptor would work, because the
> descriptors_changed() routine doesn't compare the old value of that
> string with the new value. (On the other hand, it does compare the
> iSerialNumber strings.)
Just to make sure. You mean, i should avoid changing iSerialNumber
because host will initiate usb reset and this device will probably not
survive it?
> Is there any way to read the firmware back from the device? Then you
> could check directly.
No, this device is a SoC with usb client interface based on FUSB200 core
(If i'm correct, same core as on carl9170 devices). We can't read memory
unless FW provide this service.
At power on, this device will boot from external or internal ROM and
load minimal FW. Without it, USB wont work.
If i read FW code correctly, it should be responsible for suspend and reset.
I do not have documentation, so created doc[1] based on code. From what
is see, i assume that we can reset usb from FW. There is at least two
methods:
- reset complete USB core. It looks for me like brute force, since we
will need completely reconfigure usb core.
- use TEST registers? ZM_TEST_OFFSET or ZM_PHY_TEST_SELECT_OFFSET - i
didn't played with it. So it is just assumption.
- other regs?
[1] https://github.com/qca/open-ath9k-htc-firmware/wiki/usb-regs
--
Regards,
Oleksij
^ permalink raw reply
* Re: [patch] Hostap: copying wrong data prism2_ioctl_giwaplist()
From: John W. Linville @ 2013-08-09 15:34 UTC (permalink / raw)
To: Dan Carpenter; +Cc: Jouni Malinen, linux-wireless, kernel-janitors
In-Reply-To: <20130809095231.GD29282@elgon.mountain>
Here I must insert the obligatory question:
Does anyone actually still use the hostap driver??
John
On Fri, Aug 09, 2013 at 12:52:31PM +0300, Dan Carpenter wrote:
> We want the data stored in "addr" and "qual", but the extra ampersands
> mean we are copying stack data instead.
>
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> ---
> Static checker stuff. Untested. Should probably be applied to -stable
> as well.
>
> diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
> index ac07473..e509030 100644
> --- a/drivers/net/wireless/hostap/hostap_ioctl.c
> +++ b/drivers/net/wireless/hostap/hostap_ioctl.c
> @@ -523,9 +523,9 @@ static int prism2_ioctl_giwaplist(struct net_device *dev,
>
> data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1);
>
> - memcpy(extra, &addr, sizeof(struct sockaddr) * data->length);
> + memcpy(extra, addr, sizeof(struct sockaddr) * data->length);
> data->flags = 1; /* has quality information */
> - memcpy(extra + sizeof(struct sockaddr) * data->length, &qual,
> + memcpy(extra + sizeof(struct sockaddr) * data->length, qual,
> sizeof(struct iw_quality) * data->length);
>
> kfree(addr);
>
--
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: FUSB200 xhci issue
From: Alan Stern @ 2013-08-09 14:52 UTC (permalink / raw)
To: Oleksij Rempel
Cc: Christian Lamparter, Sarah Sharp, Seth Forshee, ath9k_htc_fw,
USB list, linux-wireless
In-Reply-To: <5204FDEF.5010108@rempel-privat.de>
On Fri, 9 Aug 2013, Oleksij Rempel wrote:
> > What about a "get firmware version" sort of thing? There really should
> > be a way for the driver to tell whether the firmware has already been
> > updated.
>
> I was not able to find good direct way to check firmware version. If i
> would add some new command then i will get option like: if responding FW
> is updated; if not, then dead or old.
> How about overwriting iProduct field? Let say, if iProduct == ath9k_htc,
> then firmware is updated? Is it more or less acceptable method? I need
> to ask this because it is really new for me.
Changing the iProduct string descriptor would work, because the
descriptors_changed() routine doesn't compare the old value of that
string with the new value. (On the other hand, it does compare the
iSerialNumber strings.)
Is there any way to read the firmware back from the device? Then you
could check directly.
Alan Stern
^ permalink raw reply
* [PATCHv2 4/6] mac80211: add support for CSA in IBSS mode
From: Simon Wunderlich @ 2013-08-09 14:35 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1376058920-17779-1-git-send-email-siwu@hrz.tu-chemnitz.de>
Ths function adds the channel switch announcement implementation for the
IBSS code. It is triggered by userspace (mac80211/cfg) or by external
channel switch announcement, which have to be adopted. Both CSAs in
beacons and action frames are supported. As for AP mode, the channel
switch is applied after some time. However in IBSS mode, the channel
switch IEs are generated in the kernel.
Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
Changes to PATCHv1:
* replace cascaded if with switch
* remove remote triggerable WARN_ON (and add forgotten braces ...)
* move function declaration from earlier patch in the series to this
one
* report used BSSID in status messages
---
net/mac80211/cfg.c | 87 +++++---
net/mac80211/ibss.c | 479 ++++++++++++++++++++++++++++++++++++++------
net/mac80211/ieee80211_i.h | 5 +
net/mac80211/iface.c | 4 +
net/mac80211/rx.c | 36 +++-
net/mac80211/tx.c | 37 +++-
6 files changed, 550 insertions(+), 98 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 44449ce..701983a 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2852,30 +2852,38 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
if (!ieee80211_sdata_running(sdata))
return;
- if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
- return;
-
sdata->radar_required = sdata->csa_radar_required;
err = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
&changed);
if (WARN_ON(err < 0))
return;
- err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
- if (err < 0)
+ ieee80211_bss_info_change_notify(sdata, changed);
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP:
+ err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
+ if (err < 0)
+ return;
+ changed |= err;
+ kfree(sdata->u.ap.next_beacon);
+ sdata->u.ap.next_beacon = NULL;
+
+ ieee80211_bss_info_change_notify(sdata, err);
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ ieee80211_ibss_finish_csa(sdata);
+ break;
+ default:
+ WARN_ON(1);
return;
-
- changed |= err;
- kfree(sdata->u.ap.next_beacon);
- sdata->u.ap.next_beacon = NULL;
+ }
sdata->vif.csa_active = false;
ieee80211_wake_queues_by_reason(&sdata->local->hw,
IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
- ieee80211_bss_info_change_notify(sdata, changed);
-
cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef);
}
@@ -2923,20 +2931,56 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
if (sdata->vif.csa_active)
return -EBUSY;
- /* only handle AP for now. */
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP:
+ 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(¶ms->beacon_after);
+ if (!sdata->u.ap.next_beacon)
+ return -ENOMEM;
+
+ err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa);
+ if (err < 0) {
+ kfree(sdata->u.ap.next_beacon);
+ return err;
+ }
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ if (!sdata->vif.bss_conf.ibss_joined)
+ return -EINVAL;
+
+ if (params->chandef.width != sdata->u.ibss.chandef.width)
+ return -EINVAL;
+
+ switch (params->chandef.width) {
+ case NL80211_CHAN_WIDTH_40:
+ if (cfg80211_get_chandef_type(¶ms->chandef) !=
+ cfg80211_get_chandef_type(&sdata->u.ibss.chandef))
+ return -EINVAL;
+ case NL80211_CHAN_WIDTH_5:
+ case NL80211_CHAN_WIDTH_10:
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* changes into another band are not supported */
+ if (sdata->u.ibss.chandef.chan->band !=
+ params->chandef.chan->band)
+ return -EINVAL;
+
+ err = ieee80211_ibss_csa_beacon(sdata, params);
+ if (err < 0)
+ return err;
break;
default:
return -EOPNOTSUPP;
}
- sdata->u.ap.next_beacon = cfg80211_beacon_dup(¶ms->beacon_after);
- if (!sdata->u.ap.next_beacon)
- return -ENOMEM;
-
- sdata->csa_counter_offset_beacon = params->counter_offset_beacon;
- sdata->csa_counter_offset_presp = params->counter_offset_presp;
sdata->csa_radar_required = params->radar_required;
if (params->block_tx)
@@ -2944,10 +2988,6 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
- err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa);
- if (err < 0)
- return err;
-
local->csa_chandef = params->chandef;
sdata->vif.csa_active = true;
@@ -3001,7 +3041,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
need_offchan = true;
if (!ieee80211_is_action(mgmt->frame_control) ||
mgmt->u.action.category == WLAN_CATEGORY_PUBLIC ||
- mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED)
+ mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED ||
+ mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT)
break;
rcu_read_lock();
sta = sta_info_get(sdata, mgmt->da);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 29f1a7b..3c23522 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -34,12 +34,15 @@
#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
+static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata);
+
static struct beacon_data *
ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
const int beacon_int, const u32 basic_rates,
const u16 capability, u64 tsf,
struct cfg80211_chan_def *chandef,
- bool *have_higher_than_11mbit)
+ bool *have_higher_than_11mbit,
+ struct cfg80211_csa_settings *csa_settings)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
@@ -59,6 +62,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
2 + 8 /* max Supported Rates */ +
3 /* max DS params */ +
4 /* IBSS params */ +
+ 5 /* Channel Switch Announcement */ +
2 + (IEEE80211_MAX_SUPP_RATES - 8) +
2 + sizeof(struct ieee80211_ht_cap) +
2 + sizeof(struct ieee80211_ht_operation) +
@@ -135,6 +139,16 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
*pos++ = 0;
*pos++ = 0;
+ if (csa_settings) {
+ *pos++ = WLAN_EID_CHANNEL_SWITCH;
+ *pos++ = 3;
+ *pos++ = csa_settings->block_tx ? 1 : 0;
+ *pos++ = ieee80211_frequency_to_channel(
+ csa_settings->chandef.chan->center_freq);
+ sdata->csa_counter_offset_beacon = (pos - presp->head);
+ *pos++ = csa_settings->count;
+ }
+
/* put the remaining rates in WLAN_EID_EXT_SUPP_RATES */
if (rates_n > 8) {
*pos++ = WLAN_EID_EXT_SUPP_RATES;
@@ -273,7 +287,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates,
capability, tsf, &chandef,
- &have_higher_than_11mbit);
+ &have_higher_than_11mbit, NULL);
if (!presp)
return;
@@ -391,6 +405,110 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
tsf, false);
}
+/* must hold sdata lock */
+int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_csa_settings *csa_settings)
+{
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+ struct beacon_data *presp, *old_presp;
+ struct cfg80211_bss *cbss;
+ const struct cfg80211_bss_ies *ies;
+ u16 capability;
+ u64 tsf;
+ int ret = 0;
+
+ sdata_assert_lock(sdata);
+
+ capability = WLAN_CAPABILITY_IBSS;
+
+ if (ifibss->privacy)
+ capability |= WLAN_CAPABILITY_PRIVACY;
+
+ cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan,
+ ifibss->bssid, ifibss->ssid,
+ ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
+ WLAN_CAPABILITY_PRIVACY,
+ capability);
+
+ if (WARN_ON(!cbss)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ rcu_read_lock();
+ ies = rcu_dereference(cbss->ies);
+ tsf = ies->tsf;
+ rcu_read_unlock();
+ cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
+
+ old_presp = rcu_dereference_protected(ifibss->presp,
+ lockdep_is_held(&sdata->wdev.mtx));
+
+ presp = ieee80211_ibss_build_presp(sdata,
+ sdata->vif.bss_conf.beacon_int,
+ sdata->vif.bss_conf.basic_rates,
+ capability, tsf, &ifibss->chandef,
+ NULL, csa_settings);
+ if (!presp) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rcu_assign_pointer(ifibss->presp, presp);
+ if (old_presp)
+ kfree_rcu(old_presp, rcu_head);
+
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+ out:
+ return ret;
+}
+
+int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+ struct cfg80211_bss *cbss;
+ int err;
+ u16 capability;
+
+ sdata_lock(sdata);
+ /* update cfg80211 bss information with the new channel */
+ if (!is_zero_ether_addr(ifibss->bssid)) {
+ capability = WLAN_CAPABILITY_IBSS;
+
+ if (ifibss->privacy)
+ capability |= WLAN_CAPABILITY_PRIVACY;
+
+ cbss = cfg80211_get_bss(sdata->local->hw.wiphy,
+ ifibss->chandef.chan,
+ ifibss->bssid, ifibss->ssid,
+ ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
+ WLAN_CAPABILITY_PRIVACY,
+ capability);
+ /* XXX: should not really modify cfg80211 data */
+ if (cbss) {
+ cbss->channel = sdata->local->csa_chandef.chan;
+ cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
+ }
+ }
+
+ ifibss->chandef = sdata->local->csa_chandef;
+
+ /* generate the beacon */
+ err = ieee80211_ibss_csa_beacon(sdata, NULL);
+ sdata_unlock(sdata);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+ cancel_work_sync(&ifibss->csa_connection_drop_work);
+}
+
static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta)
__acquires(RCU)
{
@@ -474,6 +592,269 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid,
return ieee80211_ibss_finish_sta(sta);
}
+static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+ struct ieee80211_local *local = sdata->local;
+ struct cfg80211_bss *cbss;
+ struct beacon_data *presp;
+ struct sta_info *sta;
+ int active_ibss;
+ u16 capability;
+
+ active_ibss = ieee80211_sta_active_ibss(sdata);
+
+ if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
+ capability = WLAN_CAPABILITY_IBSS;
+
+ if (ifibss->privacy)
+ capability |= WLAN_CAPABILITY_PRIVACY;
+
+ cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
+ ifibss->bssid, ifibss->ssid,
+ ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
+ WLAN_CAPABILITY_PRIVACY,
+ capability);
+
+ if (cbss) {
+ cfg80211_unlink_bss(local->hw.wiphy, cbss);
+ cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
+ }
+ }
+
+ ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
+
+ sta_info_flush(sdata);
+
+ spin_lock_bh(&ifibss->incomplete_lock);
+ while (!list_empty(&ifibss->incomplete_stations)) {
+ sta = list_first_entry(&ifibss->incomplete_stations,
+ struct sta_info, list);
+ list_del(&sta->list);
+ spin_unlock_bh(&ifibss->incomplete_lock);
+
+ sta_info_free(local, sta);
+ spin_lock_bh(&ifibss->incomplete_lock);
+ }
+ spin_unlock_bh(&ifibss->incomplete_lock);
+
+ netif_carrier_off(sdata->dev);
+
+ sdata->vif.bss_conf.ibss_joined = false;
+ sdata->vif.bss_conf.ibss_creator = false;
+ sdata->vif.bss_conf.enable_beacon = false;
+ sdata->vif.bss_conf.ssid_len = 0;
+
+ /* remove beacon */
+ presp = rcu_dereference_protected(ifibss->presp,
+ lockdep_is_held(&sdata->wdev.mtx));
+ RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
+ if (presp)
+ kfree_rcu(presp, rcu_head);
+
+ clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
+ BSS_CHANGED_IBSS);
+}
+
+static void ieee80211_csa_connection_drop_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data,
+ u.ibss.csa_connection_drop_work);
+
+ ieee80211_ibss_disconnect(sdata);
+ synchronize_rcu();
+ skb_queue_purge(&sdata->skb_queue);
+
+ /* trigger a scan to find another IBSS network to join */
+ ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+}
+
+static bool
+ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
+ struct ieee802_11_elems *elems,
+ bool beacon)
+{
+ struct cfg80211_csa_settings params;
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ struct ieee80211_chanctx *chanctx;
+ enum nl80211_channel_type ch_type;
+ int err, num_chanctx;
+ u32 sta_flags;
+ u8 mode;
+
+ if (sdata->vif.csa_active)
+ return true;
+
+ if (!sdata->vif.bss_conf.ibss_joined)
+ return false;
+
+ sta_flags = IEEE80211_STA_DISABLE_VHT;
+ switch (ifibss->chandef.width) {
+ case NL80211_CHAN_WIDTH_5:
+ case NL80211_CHAN_WIDTH_10:
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ sta_flags |= IEEE80211_STA_DISABLE_HT;
+ /* fall through */
+ case NL80211_CHAN_WIDTH_20:
+ sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
+ break;
+ default:
+ break;
+ }
+
+ memset(¶ms, 0, sizeof(params));
+ err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon,
+ ifibss->chandef.chan->band,
+ sta_flags, ifibss->bssid,
+ ¶ms.count, &mode,
+ ¶ms.chandef);
+
+ /* can't switch to destination channel, fail */
+ if (err < 0)
+ goto disconnect;
+
+ /* did not contain a CSA */
+ if (err)
+ return false;
+
+ if (ifibss->chandef.chan->band != params.chandef.chan->band)
+ goto disconnect;
+
+ switch (ifibss->chandef.width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ case NL80211_CHAN_WIDTH_40:
+ /* keep our current HT mode (HT20/HT40+/HT40-), even if
+ * another mode has been announced. The mode is not adopted
+ * within the beacon while doing CSA and we should therefore
+ * keep the mode which we announce.
+ */
+ ch_type = cfg80211_get_chandef_type(&ifibss->chandef);
+ cfg80211_chandef_create(¶ms.chandef, params.chandef.chan,
+ ch_type);
+ break;
+ case NL80211_CHAN_WIDTH_5:
+ case NL80211_CHAN_WIDTH_10:
+ if (params.chandef.width != ifibss->chandef.width) {
+ sdata_info(sdata,
+ "IBSS %pM received channel switch from incompatible channel width (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
+ ifibss->bssid,
+ params.chandef.chan->center_freq,
+ params.chandef.width,
+ params.chandef.center_freq1,
+ params.chandef.center_freq2);
+ goto disconnect;
+ }
+ break;
+ default:
+ /* should not happen, sta_flags should prevent VHT modes. */
+ WARN_ON(1);
+ goto disconnect;
+ }
+
+ if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, ¶ms.chandef,
+ IEEE80211_CHAN_DISABLED)) {
+ sdata_info(sdata,
+ "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
+ ifibss->bssid,
+ params.chandef.chan->center_freq,
+ params.chandef.width,
+ params.chandef.center_freq1,
+ params.chandef.center_freq2);
+ goto disconnect;
+ }
+
+ err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
+ ¶ms.chandef);
+ if (err < 0)
+ goto disconnect;
+ if (err) {
+ params.radar_required = true;
+
+ /* TODO: IBSS-DFS not (yet) supported, disconnect. */
+ goto disconnect;
+ }
+
+ rcu_read_lock();
+ chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+ if (!chanctx_conf) {
+ rcu_read_unlock();
+ goto disconnect;
+ }
+
+ /* don't handle for multi-VIF cases */
+ chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
+ if (chanctx->refcount > 1) {
+ rcu_read_unlock();
+ goto disconnect;
+ }
+ num_chanctx = 0;
+ list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
+ num_chanctx++;
+
+ if (num_chanctx > 1) {
+ rcu_read_unlock();
+ goto disconnect;
+ }
+ rcu_read_unlock();
+
+ /* all checks done, now perform the channel switch. */
+ ibss_dbg(sdata,
+ "received channel switch announcement to go to channel %d MHz\n",
+ params.chandef.chan->center_freq);
+
+ params.block_tx = !!mode;
+
+ ieee80211_ibss_csa_beacon(sdata, ¶ms);
+ sdata->csa_radar_required = params.radar_required;
+
+ if (params.block_tx)
+ ieee80211_stop_queues_by_reason(&sdata->local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_CSA);
+
+ sdata->local->csa_chandef = params.chandef;
+ sdata->vif.csa_active = true;
+
+ ieee80211_bss_info_change_notify(sdata, err);
+ drv_channel_switch_beacon(sdata, ¶ms.chandef);
+
+ return true;
+disconnect:
+ ibss_dbg(sdata, "Can't handle channel switch, disconnect\n");
+ ieee80211_queue_work(&sdata->local->hw,
+ &ifibss->csa_connection_drop_work);
+
+ return true;
+}
+
+static void
+ieee80211_rx_mgmt_spectrum_mgmt(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt, size_t len,
+ struct ieee80211_rx_status *rx_status,
+ struct ieee802_11_elems *elems)
+{
+ int required_len;
+
+ if (len < IEEE80211_MIN_ACTION_SIZE + 1)
+ return;
+
+ /* CSA is the only action we handle for now */
+ if (mgmt->u.action.u.measurement.action_code !=
+ WLAN_ACTION_SPCT_CHL_SWITCH)
+ return;
+
+ required_len = IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.chan_switch);
+ if (len < required_len)
+ return;
+
+ ieee80211_ibss_process_chanswitch(sdata, elems, false);
+}
+
static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
size_t len)
@@ -636,10 +1017,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
/* check if we need to merge IBSS */
- /* we use a fixed BSSID */
- if (sdata->u.ibss.fixed_bssid)
- goto put_bss;
-
/* not an IBSS */
if (!(cbss->capability & WLAN_CAPABILITY_IBSS))
goto put_bss;
@@ -655,10 +1032,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
sdata->u.ibss.ssid_len))
goto put_bss;
+ /* process channel switch */
+ if (ieee80211_ibss_process_chanswitch(sdata, elems, true))
+ goto put_bss;
+
/* same BSSID */
if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid))
goto put_bss;
+ /* we use a fixed BSSID */
+ if (sdata->u.ibss.fixed_bssid)
+ goto put_bss;
+
if (ieee80211_have_rx_timestamp(rx_status)) {
/* time when timestamp field was received */
rx_timestamp =
@@ -1040,6 +1425,8 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct ieee80211_rx_status *rx_status;
struct ieee80211_mgmt *mgmt;
u16 fc;
+ struct ieee802_11_elems elems;
+ int ies_len;
rx_status = IEEE80211_SKB_RXCB(skb);
mgmt = (struct ieee80211_mgmt *) skb->data;
@@ -1065,6 +1452,27 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
case IEEE80211_STYPE_DEAUTH:
ieee80211_rx_mgmt_deauth_ibss(sdata, mgmt, skb->len);
break;
+ case IEEE80211_STYPE_ACTION:
+ switch (mgmt->u.action.category) {
+ case WLAN_CATEGORY_SPECTRUM_MGMT:
+ ies_len = skb->len -
+ offsetof(struct ieee80211_mgmt,
+ u.action.u.chan_switch.variable);
+
+ if (ies_len < 0)
+ break;
+
+ ieee802_11_parse_elems(
+ mgmt->u.action.u.chan_switch.variable,
+ ies_len, true, &elems);
+
+ if (elems.parse_error)
+ break;
+
+ ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len,
+ rx_status, &elems);
+ break;
+ }
}
mgmt_out:
@@ -1131,6 +1539,8 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
(unsigned long) sdata);
INIT_LIST_HEAD(&ifibss->incomplete_stations);
spin_lock_init(&ifibss->incomplete_lock);
+ INIT_WORK(&ifibss->csa_connection_drop_work,
+ ieee80211_csa_connection_drop_work);
}
/* scan finished notification */
@@ -1229,72 +1639,19 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- struct ieee80211_local *local = sdata->local;
- struct cfg80211_bss *cbss;
- u16 capability;
- int active_ibss;
- struct sta_info *sta;
- struct beacon_data *presp;
- active_ibss = ieee80211_sta_active_ibss(sdata);
+ ieee80211_ibss_disconnect(sdata);
- if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
- capability = WLAN_CAPABILITY_IBSS;
-
- if (ifibss->privacy)
- capability |= WLAN_CAPABILITY_PRIVACY;
-
- cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
- ifibss->bssid, ifibss->ssid,
- ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
- WLAN_CAPABILITY_PRIVACY,
- capability);
-
- if (cbss) {
- cfg80211_unlink_bss(local->hw.wiphy, cbss);
- cfg80211_put_bss(local->hw.wiphy, cbss);
- }
- }
-
- ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
- memset(ifibss->bssid, 0, ETH_ALEN);
ifibss->ssid_len = 0;
-
- sta_info_flush(sdata);
-
- spin_lock_bh(&ifibss->incomplete_lock);
- while (!list_empty(&ifibss->incomplete_stations)) {
- sta = list_first_entry(&ifibss->incomplete_stations,
- struct sta_info, list);
- list_del(&sta->list);
- spin_unlock_bh(&ifibss->incomplete_lock);
-
- sta_info_free(local, sta);
- spin_lock_bh(&ifibss->incomplete_lock);
- }
- spin_unlock_bh(&ifibss->incomplete_lock);
-
- netif_carrier_off(sdata->dev);
-
+ memset(ifibss->bssid, 0, ETH_ALEN);
/* remove beacon */
kfree(sdata->u.ibss.ie);
- presp = rcu_dereference_protected(ifibss->presp,
- lockdep_is_held(&sdata->wdev.mtx));
- RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
/* on the next join, re-program HT parameters */
memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa));
memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask));
- sdata->vif.bss_conf.ibss_joined = false;
- sdata->vif.bss_conf.ibss_creator = false;
- sdata->vif.bss_conf.enable_beacon = false;
- sdata->vif.bss_conf.ssid_len = 0;
- clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
- BSS_CHANGED_IBSS);
synchronize_rcu();
- kfree(presp);
skb_queue_purge(&sdata->skb_queue);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 98209eb..3d17333 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -487,6 +487,7 @@ struct ieee80211_if_managed {
struct ieee80211_if_ibss {
struct timer_list timer;
+ struct work_struct csa_connection_drop_work;
unsigned long last_scan_completed;
@@ -1330,6 +1331,10 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata);
void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
+int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_csa_settings *csa_settings);
+int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata);
+void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata);
/* mesh code */
void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 7ca534b..a8bce73 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -763,6 +763,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
if (sdata->vif.type == NL80211_IFTYPE_STATION)
ieee80211_mgd_stop(sdata);
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+ ieee80211_ibss_stop(sdata);
+
+
/*
* Remove all stations associated with this interface.
*
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 0ac7512..59595d6 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2396,7 +2396,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
return RX_DROP_UNUSABLE;
if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC &&
- mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED)
+ mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED &&
+ mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT)
return RX_DROP_UNUSABLE;
if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
@@ -2560,31 +2561,46 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
goto queue;
case WLAN_CATEGORY_SPECTRUM_MGMT:
- if (status->band != IEEE80211_BAND_5GHZ)
- break;
-
- if (sdata->vif.type != NL80211_IFTYPE_STATION)
- break;
-
/* verify action_code is present */
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
break;
switch (mgmt->u.action.u.measurement.action_code) {
case WLAN_ACTION_SPCT_MSR_REQ:
+ if (status->band != IEEE80211_BAND_5GHZ)
+ break;
+
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.measurement)))
break;
+
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ break;
+
ieee80211_process_measurement_req(sdata, mgmt, len);
goto handled;
- case WLAN_ACTION_SPCT_CHL_SWITCH:
- if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ case WLAN_ACTION_SPCT_CHL_SWITCH: {
+ u8 *bssid;
+ if (len < (IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.chan_switch)))
break;
- if (!ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid))
+ if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC)
+ break;
+
+ if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ bssid = sdata->u.mgd.bssid;
+ else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+ bssid = sdata->u.ibss.bssid;
+ else
+ break;
+
+ if (!ether_addr_equal(mgmt->bssid, bssid))
break;
goto queue;
+ }
}
break;
case WLAN_CATEGORY_SA_QUERY:
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 0e42322..82d5a6f 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2353,15 +2353,31 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
struct probe_resp *resp;
int counter_offset_beacon = sdata->csa_counter_offset_beacon;
int counter_offset_presp = sdata->csa_counter_offset_presp;
+ u8 *beacon_data;
+ size_t beacon_data_len;
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP:
+ beacon_data = beacon->tail;
+ beacon_data_len = beacon->tail_len;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ beacon_data = beacon->head;
+ beacon_data_len = beacon->head_len;
+ break;
+ default:
+ return;
+ }
+ if (WARN_ON(counter_offset_beacon >= beacon_data_len))
+ return;
/* warn if the driver did not check for/react to csa completeness */
- if (WARN_ON(((u8 *)beacon->tail)[counter_offset_beacon] == 0))
+ if (WARN_ON(beacon_data[counter_offset_beacon] == 0))
return;
- ((u8 *)beacon->tail)[counter_offset_beacon]--;
+ beacon_data[counter_offset_beacon]--;
- if (sdata->vif.type == NL80211_IFTYPE_AP &&
- counter_offset_presp) {
+ if (sdata->vif.type == NL80211_IFTYPE_AP && counter_offset_presp) {
rcu_read_lock();
resp = rcu_dereference(sdata->u.ap.probe_resp);
@@ -2396,6 +2412,15 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
goto out;
beacon_data = beacon->tail;
beacon_data_len = beacon->tail_len;
+ } else if (vif->type == NL80211_IFTYPE_ADHOC) {
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+ beacon = rcu_dereference(ifibss->presp);
+ if (!beacon)
+ goto out;
+
+ beacon_data = beacon->head;
+ beacon_data_len = beacon->head_len;
} else {
WARN_ON(1);
goto out;
@@ -2480,6 +2505,10 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
if (!presp)
goto out;
+ if (sdata->vif.csa_active)
+ ieee80211_update_csa(sdata, presp);
+
+
skb = dev_alloc_skb(local->tx_headroom + presp->head_len);
if (!skb)
goto out;
--
1.7.10.4
^ permalink raw reply related
* [PATCHv2 2/6] mac80211: split off channel switch parsing function
From: Simon Wunderlich @ 2013-08-09 14:35 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1376058920-17779-1-git-send-email-siwu@hrz.tu-chemnitz.de>
The channel switch parsing function can be re-used for the IBSS code,
put the common part into an extra function.
Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
Changes to PATCHv1:
* keep reporting the BSSID, this is still important debug output
* remove a function declaration which are added in a later patch
---
net/mac80211/ieee80211_i.h | 20 +++++++
net/mac80211/mlme.c | 137 +++++++++++++++++++++++++-------------------
2 files changed, 97 insertions(+), 60 deletions(-)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index b618651..98209eb 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1557,6 +1557,26 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
struct ieee802_11_elems *elems,
u64 filter, u32 crc);
+
+/**
+ * ieee80211_parse_ch_switch_ie - parses channel switch IEs
+ * @sdata: the sdata of the interface which has received the frame
+ * @elems: parsed 802.11 elements received with the frame
+ * @beacon: indicates if the frame was a beacon or probe response
+ * @current_band: indicates the current band
+ * @sta_flags: contains information about own capabilities and restrictions
+ * @count: to be filled with the counter until the switch (on success only)
+ * @bssid: the currently connected bssid (for reporting)
+ * @mode: to be filled with CSA mode (on success only)
+ * @new_chandef: to be filled with destination chandef (on success only)
+ * Return: 0 on success, <0 on error and >0 if there is nothing to parse.
+ */
+int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
+ struct ieee802_11_elems *elems, bool beacon,
+ enum ieee80211_band current_band,
+ u32 sta_flags, u8 *bssid, u8 *count, u8 *mode,
+ struct cfg80211_chan_def *new_chandef);
+
static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
bool action,
struct ieee802_11_elems *elems)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 45a87ee..32a4da0 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -981,54 +981,35 @@ static void ieee80211_chswitch_timer(unsigned long data)
ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work);
}
-static void
-ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
- u64 timestamp, struct ieee802_11_elems *elems,
- bool beacon)
+int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
+ struct ieee802_11_elems *elems, bool beacon,
+ enum ieee80211_band current_band,
+ u32 sta_flags, u8 *bssid, u8 *count, u8 *mode,
+ struct cfg80211_chan_def *new_chandef)
{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- struct cfg80211_bss *cbss = ifmgd->associated;
- struct ieee80211_bss *bss;
- struct ieee80211_chanctx *chanctx;
enum ieee80211_band new_band;
int new_freq;
u8 new_chan_no;
- u8 count;
- u8 mode;
struct ieee80211_channel *new_chan;
- struct cfg80211_chan_def new_chandef = {};
struct cfg80211_chan_def new_vht_chandef = {};
const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
const struct ieee80211_ht_operation *ht_oper;
int secondary_channel_offset = -1;
- sdata_assert_lock(sdata);
-
- if (!cbss)
- return;
-
- if (local->scanning)
- return;
-
- /* disregard subsequent announcements if we are already processing */
- if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
- return;
-
sec_chan_offs = elems->sec_chan_offs;
wide_bw_chansw_ie = elems->wide_bw_chansw_ie;
ht_oper = elems->ht_operation;
- if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
- IEEE80211_STA_DISABLE_40MHZ)) {
+ if (sta_flags & (IEEE80211_STA_DISABLE_HT |
+ IEEE80211_STA_DISABLE_40MHZ)) {
sec_chan_offs = NULL;
wide_bw_chansw_ie = NULL;
/* only used for bandwidth here */
ht_oper = NULL;
}
- if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
+ if (sta_flags & IEEE80211_STA_DISABLE_VHT)
wide_bw_chansw_ie = NULL;
if (elems->ext_chansw_ie) {
@@ -1038,33 +1019,28 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
sdata_info(sdata,
"cannot understand ECSA IE operating class %d, disconnecting\n",
elems->ext_chansw_ie->new_operating_class);
- ieee80211_queue_work(&local->hw,
- &ifmgd->csa_connection_drop_work);
+ return -EINVAL;
}
new_chan_no = elems->ext_chansw_ie->new_ch_num;
- count = elems->ext_chansw_ie->count;
- mode = elems->ext_chansw_ie->mode;
+ *count = elems->ext_chansw_ie->count;
+ *mode = elems->ext_chansw_ie->mode;
} else if (elems->ch_switch_ie) {
- new_band = cbss->channel->band;
+ new_band = current_band;
new_chan_no = elems->ch_switch_ie->new_ch_num;
- count = elems->ch_switch_ie->count;
- mode = elems->ch_switch_ie->mode;
+ *count = elems->ch_switch_ie->count;
+ *mode = elems->ch_switch_ie->mode;
} else {
/* nothing here we understand */
- return;
+ return 1;
}
- bss = (void *)cbss->priv;
-
new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);
new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) {
sdata_info(sdata,
- "AP %pM switches to unsupported channel (%d MHz), disconnecting\n",
- ifmgd->associated->bssid, new_freq);
- ieee80211_queue_work(&local->hw,
- &ifmgd->csa_connection_drop_work);
- return;
+ "BSS %pM switches to unsupported channel (%d MHz), disconnecting\n",
+ bssid, new_freq);
+ return -EINVAL;
}
if (!beacon && sec_chan_offs) {
@@ -1072,7 +1048,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
} else if (beacon && ht_oper) {
secondary_channel_offset =
ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
- } else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
+ } else if (!(sta_flags & IEEE80211_STA_DISABLE_HT)) {
/*
* If it's not a beacon, HT is enabled and the IE not present,
* it's 20 MHz, 802.11-2012 8.5.2.6:
@@ -1088,25 +1064,25 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
default:
/* secondary_channel_offset was present but is invalid */
case IEEE80211_HT_PARAM_CHA_SEC_NONE:
- cfg80211_chandef_create(&new_chandef, new_chan,
+ cfg80211_chandef_create(new_chandef, new_chan,
NL80211_CHAN_HT20);
break;
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
- cfg80211_chandef_create(&new_chandef, new_chan,
+ cfg80211_chandef_create(new_chandef, new_chan,
NL80211_CHAN_HT40PLUS);
break;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
- cfg80211_chandef_create(&new_chandef, new_chan,
+ cfg80211_chandef_create(new_chandef, new_chan,
NL80211_CHAN_HT40MINUS);
break;
case -1:
- cfg80211_chandef_create(&new_chandef, new_chan,
+ cfg80211_chandef_create(new_chandef, new_chan,
NL80211_CHAN_NO_HT);
/* keep width for 5/10 MHz channels */
switch (sdata->vif.bss_conf.chandef.width) {
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
- new_chandef.width = sdata->vif.bss_conf.chandef.width;
+ new_chandef->width = sdata->vif.bss_conf.chandef.width;
break;
default:
break;
@@ -1142,13 +1118,13 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
break;
}
- if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ &&
+ if (sta_flags & IEEE80211_STA_DISABLE_80P80MHZ &&
new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80)
chandef_downgrade(&new_vht_chandef);
- if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ &&
+ if (sta_flags & IEEE80211_STA_DISABLE_160MHZ &&
new_vht_chandef.width == NL80211_CHAN_WIDTH_160)
chandef_downgrade(&new_vht_chandef);
- if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ &&
+ if (sta_flags & IEEE80211_STA_DISABLE_40MHZ &&
new_vht_chandef.width > NL80211_CHAN_WIDTH_20)
chandef_downgrade(&new_vht_chandef);
}
@@ -1156,23 +1132,64 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
/* if VHT data is there validate & use it */
if (new_vht_chandef.chan) {
if (!cfg80211_chandef_compatible(&new_vht_chandef,
- &new_chandef)) {
+ new_chandef)) {
sdata_info(sdata,
- "AP %pM CSA has inconsistent channel data, disconnecting\n",
- ifmgd->associated->bssid);
- ieee80211_queue_work(&local->hw,
- &ifmgd->csa_connection_drop_work);
- return;
+ "BSS %pM: CSA has inconsistent channel data, disconnecting\n",
+ bssid);
+ return -EINVAL;
}
- new_chandef = new_vht_chandef;
+ *new_chandef = new_vht_chandef;
}
+ return 0;
+}
+
+static void
+ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
+ u64 timestamp, struct ieee802_11_elems *elems,
+ bool beacon)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ struct cfg80211_bss *cbss = ifmgd->associated;
+ struct ieee80211_chanctx *chanctx;
+ enum ieee80211_band current_band;
+ u8 count;
+ u8 mode;
+ struct cfg80211_chan_def new_chandef = {};
+ int res;
+
+ sdata_assert_lock(sdata);
+
+ if (!cbss)
+ return;
+
+ if (local->scanning)
+ return;
+
+ /* disregard subsequent announcements if we are already processing */
+ if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
+ return;
+
+ current_band = cbss->channel->band;
+ res = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, current_band,
+ ifmgd->flags,
+ ifmgd->associated->bssid, &count,
+ &mode, &new_chandef);
+ if (res < 0)
+ ieee80211_queue_work(&local->hw,
+ &ifmgd->csa_connection_drop_work);
+ if (res)
+ return;
+
if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef,
IEEE80211_CHAN_DISABLED)) {
sdata_info(sdata,
"AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
- ifmgd->associated->bssid, new_freq,
- new_chandef.width, new_chandef.center_freq1,
+ ifmgd->associated->bssid,
+ new_chandef.chan->center_freq,
+ new_chandef.width,
+ new_chandef.center_freq1,
new_chandef.center_freq2);
ieee80211_queue_work(&local->hw,
&ifmgd->csa_connection_drop_work);
--
1.7.10.4
^ permalink raw reply related
* [PATCHv2 3/6] mac80211: move ibss presp generation in own function
From: Simon Wunderlich @ 2013-08-09 14:35 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1376058920-17779-1-git-send-email-siwu@hrz.tu-chemnitz.de>
Channel Switch will later require to generate beacons without setting
them immediately. Therefore split the presp generation in an own
function. Splitting the original very long function might be a good idea
anyway.
Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
net/mac80211/ibss.c | 185 ++++++++++++++++++++++++++++++---------------------
1 file changed, 109 insertions(+), 76 deletions(-)
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index e08387c..29f1a7b 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -34,13 +34,12 @@
#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
-
-static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
- const u8 *bssid, const int beacon_int,
- struct ieee80211_channel *chan,
- const u32 basic_rates,
- const u16 capability, u64 tsf,
- bool creator)
+static struct beacon_data *
+ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
+ const int beacon_int, const u32 basic_rates,
+ const u16 capability, u64 tsf,
+ struct cfg80211_chan_def *chandef,
+ bool *have_higher_than_11mbit)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
@@ -48,70 +47,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt;
u8 *pos;
struct ieee80211_supported_band *sband;
- struct cfg80211_bss *bss;
- u32 bss_change, rate_flags, rates = 0, rates_added = 0;
- struct cfg80211_chan_def chandef;
- enum nl80211_bss_scan_width scan_width;
- bool have_higher_than_11mbit = false;
+ u32 rate_flags, rates = 0, rates_added = 0;
struct beacon_data *presp;
int frame_len;
int shift;
- sdata_assert_lock(sdata);
-
- /* Reset own TSF to allow time synchronization work. */
- drv_reset_tsf(local, sdata);
-
- if (!ether_addr_equal(ifibss->bssid, bssid))
- sta_info_flush(sdata);
-
- /* if merging, indicate to driver that we leave the old IBSS */
- if (sdata->vif.bss_conf.ibss_joined) {
- sdata->vif.bss_conf.ibss_joined = false;
- sdata->vif.bss_conf.ibss_creator = false;
- sdata->vif.bss_conf.enable_beacon = false;
- netif_carrier_off(sdata->dev);
- ieee80211_bss_info_change_notify(sdata,
- BSS_CHANGED_IBSS |
- BSS_CHANGED_BEACON_ENABLED);
- }
-
- presp = rcu_dereference_protected(ifibss->presp,
- lockdep_is_held(&sdata->wdev.mtx));
- rcu_assign_pointer(ifibss->presp, NULL);
- if (presp)
- kfree_rcu(presp, rcu_head);
-
- sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
-
- chandef = ifibss->chandef;
- if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
- if (chandef.width == NL80211_CHAN_WIDTH_5 ||
- chandef.width == NL80211_CHAN_WIDTH_10 ||
- chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
- chandef.width == NL80211_CHAN_WIDTH_20) {
- sdata_info(sdata,
- "Failed to join IBSS, beacons forbidden\n");
- return;
- }
- chandef.width = NL80211_CHAN_WIDTH_20;
- chandef.center_freq1 = chan->center_freq;
- }
-
- ieee80211_vif_release_channel(sdata);
- if (ieee80211_vif_use_channel(sdata, &chandef,
- ifibss->fixed_channel ?
- IEEE80211_CHANCTX_SHARED :
- IEEE80211_CHANCTX_EXCLUSIVE)) {
- sdata_info(sdata, "Failed to join IBSS, no channel context\n");
- return;
- }
-
- memcpy(ifibss->bssid, bssid, ETH_ALEN);
-
- sband = local->hw.wiphy->bands[chan->band];
- shift = ieee80211_vif_get_shift(&sdata->vif);
-
/* Build IBSS probe response */
frame_len = sizeof(struct ieee80211_hdr_3addr) +
12 /* struct ieee80211_mgmt.u.beacon */ +
@@ -125,7 +65,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
ifibss->ie_len;
presp = kzalloc(sizeof(*presp) + frame_len, GFP_KERNEL);
if (!presp)
- return;
+ return NULL;
presp->head = (void *)(presp + 1);
@@ -146,12 +86,19 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
memcpy(pos, ifibss->ssid, ifibss->ssid_len);
pos += ifibss->ssid_len;
- rate_flags = ieee80211_chandef_rate_flags(&chandef);
+ sband = local->hw.wiphy->bands[chandef->chan->band];
+ rate_flags = ieee80211_chandef_rate_flags(chandef);
+ shift = ieee80211_chandef_get_shift(chandef);
+ rates_n = 0;
+ if (have_higher_than_11mbit)
+ *have_higher_than_11mbit = false;
+
for (i = 0; i < sband->n_bitrates; i++) {
if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
continue;
- if (sband->bitrates[i].bitrate > 110)
- have_higher_than_11mbit = true;
+ if (sband->bitrates[i].bitrate > 110 &&
+ have_higher_than_11mbit)
+ *have_higher_than_11mbit = true;
rates |= BIT(i);
rates_n++;
@@ -178,7 +125,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
if (sband->band == IEEE80211_BAND_2GHZ) {
*pos++ = WLAN_EID_DS_PARAMS;
*pos++ = 1;
- *pos++ = ieee80211_frequency_to_channel(chan->center_freq);
+ *pos++ = ieee80211_frequency_to_channel(
+ chandef->chan->center_freq);
}
*pos++ = WLAN_EID_IBSS_PARAMS;
@@ -210,9 +158,9 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
}
/* add HT capability and information IEs */
- if (chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
- chandef.width != NL80211_CHAN_WIDTH_5 &&
- chandef.width != NL80211_CHAN_WIDTH_10 &&
+ if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT &&
+ chandef->width != NL80211_CHAN_WIDTH_5 &&
+ chandef->width != NL80211_CHAN_WIDTH_10 &&
sband->ht_cap.ht_supported) {
struct ieee80211_sta_ht_cap ht_cap;
@@ -226,7 +174,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
* keep them at 0
*/
pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
- &chandef, 0);
+ chandef, 0);
}
if (local->hw.queues >= IEEE80211_NUM_ACS) {
@@ -243,9 +191,94 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
presp->head_len = pos - presp->head;
if (WARN_ON(presp->head_len > frame_len))
+ goto error;
+
+ return presp;
+error:
+ kfree(presp);
+ return NULL;
+}
+
+static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
+ const u8 *bssid, const int beacon_int,
+ struct ieee80211_channel *chan,
+ const u32 basic_rates,
+ const u16 capability, u64 tsf,
+ bool creator)
+{
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_mgmt *mgmt;
+ struct cfg80211_bss *bss;
+ u32 bss_change;
+ struct cfg80211_chan_def chandef;
+ struct beacon_data *presp;
+ enum nl80211_bss_scan_width scan_width;
+ bool have_higher_than_11mbit;
+
+ sdata_assert_lock(sdata);
+
+ /* Reset own TSF to allow time synchronization work. */
+ drv_reset_tsf(local, sdata);
+
+ if (!ether_addr_equal(ifibss->bssid, bssid))
+ sta_info_flush(sdata);
+
+ /* if merging, indicate to driver that we leave the old IBSS */
+ if (sdata->vif.bss_conf.ibss_joined) {
+ sdata->vif.bss_conf.ibss_joined = false;
+ sdata->vif.bss_conf.ibss_creator = false;
+ sdata->vif.bss_conf.enable_beacon = false;
+ netif_carrier_off(sdata->dev);
+ ieee80211_bss_info_change_notify(sdata,
+ BSS_CHANGED_IBSS |
+ BSS_CHANGED_BEACON_ENABLED);
+ }
+
+ presp = rcu_dereference_protected(ifibss->presp,
+ lockdep_is_held(&sdata->wdev.mtx));
+ rcu_assign_pointer(ifibss->presp, NULL);
+ if (presp)
+ kfree_rcu(presp, rcu_head);
+
+ sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
+
+ chandef = ifibss->chandef;
+ if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
+ if (chandef.width == NL80211_CHAN_WIDTH_5 ||
+ chandef.width == NL80211_CHAN_WIDTH_10 ||
+ chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
+ chandef.width == NL80211_CHAN_WIDTH_20) {
+ sdata_info(sdata,
+ "Failed to join IBSS, beacons forbidden\n");
+ return;
+ }
+ chandef.width = NL80211_CHAN_WIDTH_20;
+ chandef.center_freq1 = chan->center_freq;
+ }
+
+ ieee80211_vif_release_channel(sdata);
+ if (ieee80211_vif_use_channel(sdata, &chandef,
+ ifibss->fixed_channel ?
+ IEEE80211_CHANCTX_SHARED :
+ IEEE80211_CHANCTX_EXCLUSIVE)) {
+ sdata_info(sdata, "Failed to join IBSS, no channel context\n");
+ return;
+ }
+
+ memcpy(ifibss->bssid, bssid, ETH_ALEN);
+
+ sband = local->hw.wiphy->bands[chan->band];
+
+ presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates,
+ capability, tsf, &chandef,
+ &have_higher_than_11mbit);
+ if (!presp)
return;
rcu_assign_pointer(ifibss->presp, presp);
+ mgmt = (void *)presp->head;
sdata->vif.bss_conf.enable_beacon = true;
sdata->vif.bss_conf.beacon_int = beacon_int;
--
1.7.10.4
^ permalink raw reply related
* [PATCHv2 6/6] nl80211: enable IBSS support for channel switch announcements
From: Simon Wunderlich @ 2013-08-09 14:35 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1376058920-17779-1-git-send-email-siwu@hrz.tu-chemnitz.de>
Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
net/wireless/nl80211.c | 49 +++++++++++++++++++++++++++++++++---------------
1 file changed, 34 insertions(+), 15 deletions(-)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f7cb121..6d3d788 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5632,15 +5632,26 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
u8 radar_detect_width = 0;
int err;
+ bool need_new_beacon = false;
if (!rdev->ops->channel_switch ||
!(rdev->wiphy.flags & WIPHY_FLAG_HAS_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)
+ switch (dev->ieee80211_ptr->iftype) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ need_new_beacon = true;
+
+ /* useless if AP is not running */
+ if (!wdev->beacon_interval)
+ return -EINVAL;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ break;
+ default:
return -EOPNOTSUPP;
+ }
memset(¶ms, 0, sizeof(params));
@@ -5649,15 +5660,16 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
/* only important for AP, IBSS and mesh create IEs internally */
- if (!info->attrs[NL80211_ATTR_CSA_IES])
- return -EINVAL;
-
- /* useless if AP is not running */
- if (!wdev->beacon_interval)
+ if (need_new_beacon &&
+ (!info->attrs[NL80211_ATTR_CSA_IES] ||
+ !info->attrs[NL80211_ATTR_CSA_C_OFF_BEACON]))
return -EINVAL;
params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
+ if (!need_new_beacon)
+ goto skip_beacons;
+
err = nl80211_parse_beacon(info->attrs, ¶ms.beacon_after);
if (err)
return err;
@@ -5697,6 +5709,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}
+skip_beacons:
err = nl80211_parse_chandef(rdev, info, ¶ms.chandef);
if (err)
return err;
@@ -5704,12 +5717,17 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef))
return -EINVAL;
- err = cfg80211_chandef_dfs_required(wdev->wiphy, ¶ms.chandef);
- if (err < 0) {
- return err;
- } else if (err) {
- radar_detect_width = BIT(params.chandef.width);
- params.radar_required = true;
+ /* DFS channels are only supported for AP/P2P GO ... for now. */
+ if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP ||
+ dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
+ err = cfg80211_chandef_dfs_required(wdev->wiphy,
+ ¶ms.chandef);
+ if (err < 0) {
+ return err;
+ } else if (err) {
+ radar_detect_width = BIT(params.chandef.width);
+ params.radar_required = true;
+ }
}
err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
@@ -10725,7 +10743,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
wdev_lock(wdev);
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
- wdev->iftype != NL80211_IFTYPE_P2P_GO))
+ wdev->iftype != NL80211_IFTYPE_P2P_GO &&
+ wdev->iftype != NL80211_IFTYPE_ADHOC))
goto out;
wdev->channel = chandef->chan;
--
1.7.10.4
^ permalink raw reply related
* [PATCHv2 0/6] add IBSS channel switch announcement support
From: Simon Wunderlich @ 2013-08-09 14:35 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Mathias Kretschmer, Simon Wunderlich
This is the second iteration of channel switch support for IBSS mode patchset
(thanks Johannes for comments). CSA for IBSS will be required for IBSS-DFS support
later. The patchset builds on top of the previously submitted AP DFS patchset.
Changes:
* patch "mac80211: fix ieee80211_sta_process_chanswitch for 5/10 MHz channels"
already applied, and therefore removed from this patchset
* report BSSID of connected network for CSA status errors
* removed (theoretically) remotely triggerable WARN_ON
* style changes (removed newline, if -> switch, move declaration in right patch)
The rough design is:
* Userspace may request to change channel using the already introduced
NL80211_CMD_CHANNEL_SWITCH command. Unlike AP mode, it does not contain
IEs or offset for CSA elements, because this is to be generated by the kernel.
* Also other stations may request a channel change by sending (E)CSA within
beacons or action frames. This is parsed and further handled as if it would
have come from userspace.
* When performing a channel switch, an action frame is sent, because beaconing
is distributed among IBSS peers and might be lost early. Furthermore,
channel switch announcement IEs are added to the beacon/probe response.
* When a channel switch could was not understood, it disconnects from the
IBSS and tries to re-connect.
Discussion points:
* When disconnecting from the IBSS because a channel switch announcement was
bogus or not understood, we might reconnect to the same BSS again - on the
old channel, because the other stas are still there, and stay there.
Although it is "accepted behaviour" in IEEE 802.11 that not all station
could make it, we should consider ignoring beacons/presp if they include CSAs
when scanning for networks to prevent this problem.
As always, any comments are appreciated.
Cheers,
Simon
Simon Wunderlich (6):
cfg80211: export cfg80211_chandef_dfs_required
mac80211: split off channel switch parsing function
mac80211: move ibss presp generation in own function
mac80211: add support for CSA in IBSS mode
mac80211: send a CSA action frame when changing channel
nl80211: enable IBSS support for channel switch announcements
include/net/cfg80211.h | 9 +
net/mac80211/cfg.c | 87 ++++--
net/mac80211/ibss.c | 719 +++++++++++++++++++++++++++++++++++---------
net/mac80211/ieee80211_i.h | 25 ++
net/mac80211/iface.c | 4 +
net/mac80211/mlme.c | 137 +++++----
net/mac80211/rx.c | 36 ++-
net/mac80211/tx.c | 37 ++-
net/wireless/chan.c | 1 +
net/wireless/core.h | 9 -
net/wireless/nl80211.c | 49 ++-
11 files changed, 858 insertions(+), 255 deletions(-)
--
1.7.10.4
^ permalink raw reply
* [PATCHv2 1/6] cfg80211: export cfg80211_chandef_dfs_required
From: Simon Wunderlich @ 2013-08-09 14:35 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1376058920-17779-1-git-send-email-siwu@hrz.tu-chemnitz.de>
It will be used later by the IBSS CSA implementation of mac80211.
Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
Changes to PATCHv1:
* remove one more newline in net/wireless/core.h
---
include/net/cfg80211.h | 9 +++++++++
net/wireless/chan.c | 1 +
net/wireless/core.h | 9 ---------
3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index b7495c7..3dd8fa3 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -437,6 +437,15 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
u32 prohibited_flags);
/**
+ * cfg80211_chandef_dfs_required - checks if radar detection is required
+ * @wiphy: the wiphy to validate against
+ * @chandef: the channel definition to check
+ * Return: 1 if radar detection is required, 0 if it is not, < 0 on error
+ */
+int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
+ const struct cfg80211_chan_def *c);
+
+/**
* ieee80211_chandef_rate_flags - returns rate flags for a channel
*
* In some channel types, not all rates may be used - for example CCK
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 50f6195..16f3c3a 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -328,6 +328,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2,
width);
}
+EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
u32 center_freq, u32 bandwidth,
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 9ad43c6..b43efac 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -382,15 +382,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
enum cfg80211_chan_mode chanmode,
u8 radar_detect);
-/**
- * cfg80211_chandef_dfs_required - checks if radar detection is required
- * @wiphy: the wiphy to validate against
- * @chandef: the channel definition to check
- * Return: 1 if radar detection is required, 0 if it is not, < 0 on error
- */
-int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
- const struct cfg80211_chan_def *c);
-
void cfg80211_set_dfs_state(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef,
enum nl80211_dfs_state dfs_state);
--
1.7.10.4
^ permalink raw reply related
* [PATCHv2 5/6] mac80211: send a CSA action frame when changing channel
From: Simon Wunderlich @ 2013-08-09 14:35 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1376058920-17779-1-git-send-email-siwu@hrz.tu-chemnitz.de>
IBSS members may not immediately be able to send out their beacon when
performing CSA, therefore also send a CSA action frame.
Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
net/mac80211/ibss.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 3c23522..cbd55f6 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -405,6 +405,61 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
tsf, false);
}
+static int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_csa_settings *csa_settings)
+{
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+ struct ieee80211_local *local = sdata->local;
+ int freq;
+ int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.chan_switch) +
+ sizeof(mgmt->u.action.u.chan_switch);
+ u8 *pos;
+
+ skb = dev_alloc_skb(local->tx_headroom + hdr_len +
+ 5 + /* channel switch announcement element */
+ 3); /* secondary channel offset element */
+ if (!skb)
+ return -1;
+
+ skb_reserve(skb, local->tx_headroom);
+ mgmt = (struct ieee80211_mgmt *)skb_put(skb, hdr_len);
+ memset(mgmt, 0, hdr_len);
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION);
+
+ eth_broadcast_addr(mgmt->da);
+ memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
+ memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
+ mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
+ mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH;
+ pos = skb_put(skb, 5);
+ *pos++ = WLAN_EID_CHANNEL_SWITCH; /* EID */
+ *pos++ = 3; /* IE length */
+ *pos++ = csa_settings->block_tx ? 1 : 0; /* CSA mode */
+ freq = csa_settings->chandef.chan->center_freq;
+ *pos++ = ieee80211_frequency_to_channel(freq); /* channel */
+ *pos++ = csa_settings->count; /* count */
+
+ if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_40) {
+ enum nl80211_channel_type ch_type;
+
+ skb_put(skb, 3);
+ *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */
+ *pos++ = 1; /* IE length */
+ ch_type = cfg80211_get_chandef_type(&csa_settings->chandef);
+ if (ch_type == NL80211_CHAN_HT40PLUS)
+ *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ else
+ *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ }
+
+ ieee80211_tx_skb(sdata, skb);
+ return 0;
+}
+
+
/* must hold sdata lock */
int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
struct cfg80211_csa_settings *csa_settings)
@@ -458,6 +513,12 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
if (old_presp)
kfree_rcu(old_presp, rcu_head);
+ /* it might not send the beacon for a while. send an action frame
+ * immediately to announce the channel switch.
+ */
+ if (csa_settings)
+ ieee80211_send_action_csa(sdata, csa_settings);
+
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
out:
return ret;
--
1.7.10.4
^ permalink raw reply related
* Re: FUSB200 xhci issue
From: Oleksij Rempel @ 2013-08-09 14:34 UTC (permalink / raw)
To: Alan Stern
Cc: Christian Lamparter, Sarah Sharp, Seth Forshee, ath9k_htc_fw,
USB list, linux-wireless
In-Reply-To: <Pine.LNX.4.44L0.1308091011130.1405-100000@iolanthe.rowland.org>
Am 09.08.2013 16:13, schrieb Alan Stern:
> On Fri, 9 Aug 2013, Christian Lamparter wrote:
>
>>> After loading firmware, a reset generally is necessary. Some devices
>>> will do it themselves; others require you to call usb_reset_device().
>>
>> This makes things complicated. Because, as far as I remember,
>> usb_reset_device() will cause the current driver to be unbound
>> unless its called during .probe, right?
>
> If the driver defines pre_reset and post_reset methods, it won't get
> unbound during a reset.
>
>> You see, ath9k_htc loads its firmware asynchronously in ".probe"
>> (ath9k_htc's .probe routine finishes before the firmware is
>> retrieved via the firmware loader helper... so part of the
>> firmware download is done in a firmware_complete callback
>> on a workqueue).
>>
>> So, if we call usb_reset_device there and the driver is unbound
>> and later rebound. the next ath9k_htc .probe will start again and
>> again and again not knowing that it is already initialized
>> (and we have a loop).
>>
>>
>> This could be solved, if the devices changes the usb-id again
>> when a proper "wifi" ath9k_htc firmware was downloaded. So, the
>> driver would know that it doesn't have to download and reset
>> the device... But we need a "free" USB-ID for that.
>
> What about a "get firmware version" sort of thing? There really should
> be a way for the driver to tell whether the firmware has already been
> updated.
I was not able to find good direct way to check firmware version. If i
would add some new command then i will get option like: if responding FW
is updated; if not, then dead or old.
How about overwriting iProduct field? Let say, if iProduct == ath9k_htc,
then firmware is updated? Is it more or less acceptable method? I need
to ask this because it is really new for me.
--
Regards,
Oleksij
^ permalink raw reply
* ath9k_htc firmware problem [was: Re: FUSB200 xhci issue]
From: Alan Stern @ 2013-08-09 14:32 UTC (permalink / raw)
To: Sujith Manoharan
Cc: Christian Lamparter, Oleksij Rempel, Sarah Sharp, Seth Forshee,
ath9k_htc_fw, USB list, linux-wireless
In-Reply-To: <20996.22876.834304.94010@gargle.gargle.HOWL>
On Fri, 9 Aug 2013, Sujith Manoharan wrote:
> Christian Lamparter wrote:
> > So, if we call usb_reset_device there and the driver is unbound
> > and later rebound. the next ath9k_htc .probe will start again and
> > again and again not knowing that it is already initialized
> > (and we have a loop).
>
> The HW/FW is buggy and this workaround is required:
> http://marc.info/?l=linux-usb&m=127960864905646&w=2
I see the problem. The device loses its firmware when it gets reset or
its port is disabled. This is really a very serious bug. For one
thing, it means the device cannot support runtime PM. (Not unless the
driver caches a copy of the firmware and reloads it every time the
device resumes.) IMO a bug like this should disqualify the device from
being allowed to wear the USB logo.
One way around the problem might be for the firmware-loading thread to
issue a usb_set_configuration call to switch to config 0 (i.e., to
unconfigure the device), then patch the host's copy of the descriptor,
and then switch back to the original configuration.
This _will_ unbind and rebind the driver, so it definitely will need a
way to tell whether the firmware has already been loaded.
Alan Stern
^ permalink raw reply
* Re: FUSB200 xhci issue
From: Alan Stern @ 2013-08-09 14:13 UTC (permalink / raw)
To: Christian Lamparter
Cc: Oleksij Rempel, Sarah Sharp, Seth Forshee, ath9k_htc_fw, USB list,
linux-wireless
In-Reply-To: <201308090006.07690.chunkeey@googlemail.com>
On Fri, 9 Aug 2013, Christian Lamparter wrote:
> > After loading firmware, a reset generally is necessary. Some devices
> > will do it themselves; others require you to call usb_reset_device().
>
> This makes things complicated. Because, as far as I remember,
> usb_reset_device() will cause the current driver to be unbound
> unless its called during .probe, right?
If the driver defines pre_reset and post_reset methods, it won't get
unbound during a reset.
> You see, ath9k_htc loads its firmware asynchronously in ".probe"
> (ath9k_htc's .probe routine finishes before the firmware is
> retrieved via the firmware loader helper... so part of the
> firmware download is done in a firmware_complete callback
> on a workqueue).
>
> So, if we call usb_reset_device there and the driver is unbound
> and later rebound. the next ath9k_htc .probe will start again and
> again and again not knowing that it is already initialized
> (and we have a loop).
>
>
> This could be solved, if the devices changes the usb-id again
> when a proper "wifi" ath9k_htc firmware was downloaded. So, the
> driver would know that it doesn't have to download and reset
> the device... But we need a "free" USB-ID for that.
What about a "get firmware version" sort of thing? There really should
be a way for the driver to tell whether the firmware has already been
updated.
Alan Stern
^ permalink raw reply
* Re: linux-next: Tree for Aug 7
From: Phil Sutter @ 2013-08-09 13:58 UTC (permalink / raw)
To: David Miller
Cc: eric.dumazet, johannes, sedat.dilek, sfr, linux-next,
linux-kernel, netdev, hannes, linux-wireless, linville
In-Reply-To: <20130807.163621.84433966934449459.davem@davemloft.net>
On Wed, Aug 07, 2013 at 04:36:21PM -0700, David Miller wrote:
> From: David Miller <davem@davemloft.net>
> Date: Wed, 07 Aug 2013 16:27:48 -0700 (PDT)
>
> > Look, I'm going to fix this myself, because I'm pretty tired of
> > waiting for the obvious fix.
>
> Someone please test this:
>
> diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
> index c623861..afc02a6 100644
> --- a/include/linux/etherdevice.h
> +++ b/include/linux/etherdevice.h
> @@ -29,6 +29,7 @@
>
> #ifdef __KERNEL__
> extern __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
> +extern __be16 __eth_type_trans(struct sk_buff *skb, struct net_device *dev);
> extern const struct header_ops eth_header_ops;
>
> extern int eth_header(struct sk_buff *skb, struct net_device *dev,
> diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
> index be1f64d..35dc1be 100644
> --- a/net/ethernet/eth.c
> +++ b/net/ethernet/eth.c
> @@ -146,6 +146,45 @@ int eth_rebuild_header(struct sk_buff *skb)
> EXPORT_SYMBOL(eth_rebuild_header);
>
> /**
> + * __eth_type_trans - only determine the packet's protocol ID.
> + * @skb: packet
> + * @dev: device
> + */
> +__be16 __eth_type_trans(struct sk_buff *skb, struct net_device *dev)
> +{
> + struct ethhdr *eth = (struct ethhdr *) skb->data;
> +
> + /*
> + * Some variants of DSA tagging don't have an ethertype field
> + * at all, so we check here whether one of those tagging
> + * variants has been configured on the receiving interface,
> + * and if so, set skb->protocol without looking at the packet.
> + */
> + if (netdev_uses_dsa_tags(dev))
> + return htons(ETH_P_DSA);
> + if (netdev_uses_trailer_tags(dev))
> + return htons(ETH_P_TRAILER);
> +
> + if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN)
> + return eth->h_proto;
> +
> + /*
> + * This is a magic hack to spot IPX packets. Older Novell breaks
> + * the protocol design and runs IPX over 802.3 without an 802.2 LLC
> + * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
> + * won't work for fault tolerant netware but does for the rest.
> + */
> + if (skb->len >= 2 && *(unsigned short *)(skb->data) == 0xFFFF)
> + return htons(ETH_P_802_3);
> +
> + /*
> + * Real 802.2 LLC
> + */
> + return htons(ETH_P_802_2);
> +}
> +EXPORT_SYMBOL(__eth_type_trans);
> +
> +/**
> * eth_type_trans - determine the packet's protocol ID.
> * @skb: received socket data
> * @dev: receiving network device
> @@ -184,33 +223,7 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
> skb->pkt_type = PACKET_OTHERHOST;
> }
>
> - /*
> - * Some variants of DSA tagging don't have an ethertype field
> - * at all, so we check here whether one of those tagging
> - * variants has been configured on the receiving interface,
> - * and if so, set skb->protocol without looking at the packet.
> - */
> - if (netdev_uses_dsa_tags(dev))
> - return htons(ETH_P_DSA);
> - if (netdev_uses_trailer_tags(dev))
> - return htons(ETH_P_TRAILER);
> -
> - if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN)
> - return eth->h_proto;
> -
> - /*
> - * This is a magic hack to spot IPX packets. Older Novell breaks
> - * the protocol design and runs IPX over 802.3 without an 802.2 LLC
> - * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
> - * won't work for fault tolerant netware but does for the rest.
> - */
> - if (skb->len >= 2 && *(unsigned short *)(skb->data) == 0xFFFF)
> - return htons(ETH_P_802_3);
> -
> - /*
> - * Real 802.2 LLC
> - */
> - return htons(ETH_P_802_2);
> + return __eth_type_trans(skb, dev);
> }
> EXPORT_SYMBOL(eth_type_trans);
>
> diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
> index 0c0f6c9..ec8e1c3 100644
> --- a/net/packet/af_packet.c
> +++ b/net/packet/af_packet.c
> @@ -2003,7 +2003,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
> return err;
>
> if (dev->type == ARPHRD_ETHER)
> - skb->protocol = eth_type_trans(skb, dev);
> + skb->protocol = __eth_type_trans(skb, dev);
>
> data += dev->hard_header_len;
> to_write -= dev->hard_header_len;
> @@ -2332,13 +2332,13 @@ static int packet_snd(struct socket *sock,
> sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
>
> if (dev->type == ARPHRD_ETHER) {
> - skb->protocol = eth_type_trans(skb, dev);
> + skb->protocol = __eth_type_trans(skb, dev);
> if (skb->protocol == htons(ETH_P_8021Q))
> reserve += VLAN_HLEN;
> } else {
> skb->protocol = proto;
> - skb->dev = dev;
> }
> + skb->dev = dev;
>
> if (!gso_type && (len > dev->mtu + reserve + extra_len)) {
> err = -EMSGSIZE;
The problem with this patch is __eth_type_trans() assuming the MAC
header at skb->data which might be correct in the most cases, but not
when called from eth_type_trans() as the later sets skb->data to after
the ethernet header (which was the problem from the beginning).
Best wishes, Phil
^ permalink raw reply
* Re: [PATCH 5/7] mac80211: add support for CSA in IBSS mode
From: Johannes Berg @ 2013-08-09 13:22 UTC (permalink / raw)
To: Simon Wunderlich; +Cc: linux-wireless, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1375457886-7275-6-git-send-email-siwu@hrz.tu-chemnitz.de>
On Fri, 2013-08-02 at 17:38 +0200, Simon Wunderlich wrote:
> + if (sdata->vif.type == NL80211_IFTYPE_AP) {
> + } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
> + } else {
switch() ?
> + case NL80211_CHAN_WIDTH_10:
> + if (WARN_ON(params.chandef.width != ifibss->chandef.width))
You should really not make a WARN_ON remotely triggerable.
johannes
^ permalink raw reply
* Re: [PATCH 3/7] mac80211: split off channel switch parsing function
From: Johannes Berg @ 2013-08-09 13:20 UTC (permalink / raw)
To: Simon Wunderlich; +Cc: linux-wireless, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1375457886-7275-4-git-send-email-siwu@hrz.tu-chemnitz.de>
On Fri, 2013-08-02 at 17:38 +0200, Simon Wunderlich wrote:
> sdata_info(sdata,
> + "network switches to unsupported channel (%d MHz), disconnecting\n",
> + new_freq);
> + return -EINVAL;
I don't like these messaging changes - it's actually interesting what
the AP is etc.
johannes
^ permalink raw reply
* Re: [PATCH 2/7] mac80211: fix ieee80211_sta_process_chanswitch for 5/10 MHz channels
From: Johannes Berg @ 2013-08-09 13:17 UTC (permalink / raw)
To: Simon Wunderlich; +Cc: linux-wireless, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1375457886-7275-3-git-send-email-siwu@hrz.tu-chemnitz.de>
Applied.
johannes
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox