* Re: [PATCH] mac80211: allow mgmt frame transmission on DFS channels
From: Lorenzo Bianconi @ 2013-10-02 10:07 UTC (permalink / raw)
To: Johannes Berg; +Cc: John Linville, Simon Wunderlich, linux-wireless
In-Reply-To: <1380704100.13329.6.camel@jlt4.sipsolutions.net>
Before start beaconing cfg80211_reg_can_beacon() verifies the channel
is CAC checked and available calling cfg80211_secondary_chans_ok().
Although the channel is marked NL80211_DFS_AVAILABLE after a CAC
period, ieee80211_monitor_start_xmit() does not allow to inject mgmt
frames on DFS channels causing association failures.
Lorenzo
2013/10/2 Johannes Berg <johannes@sipsolutions.net>:
> On Mon, 2013-09-30 at 14:52 +0200, Lorenzo Bianconi wrote:
>> Allow management frame injection on DFS channels if the channel has been CAC
>> checked and is available
>
>> +++ b/net/mac80211/tx.c
>> @@ -1694,8 +1694,10 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
>> * radar detection by itself. We can do that later by adding a
>> * monitor flag interfaces used for AP support.
>> */
>> - if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
>> - IEEE80211_CHAN_PASSIVE_SCAN)))
>> + if (((chan->flags & (IEEE80211_CHAN_PASSIVE_SCAN |
>> + IEEE80211_CHAN_NO_IBSS))) ||
>> + ((chan->flags & IEEE80211_CHAN_RADAR) &&
>> + chan->dfs_state != NL80211_DFS_AVAILABLE))
>
> This would be the only place where mac80211 is accessing
> chan->dfs_state, does that make sense? Why is it not needed elsewhere?
>
> johannes
>
--
UNIX is Sexy: who | grep -i blonde | talk; cd ~; wine; talk; touch;
unzip; touch; strip; gasp; finger; gasp; mount; fsck; more; yes; gasp;
umount; make clean; sleep
^ permalink raw reply
* [PATCH] ath10k: fix scheduling while atomic bug on config
From: Michal Kazior @ 2013-10-02 9:51 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Michal Kazior
Recent WMI/HTC changes introduces this bug because
now WMI commands can sleep.
Use appropriate interface iteration function.
Reported-By: Kalle Valo <kvalo@qca.qualcomm.com>
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
drivers/net/wireless/ath/ath10k/mac.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 8684e03..b65df84 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1935,9 +1935,8 @@ static void ath10k_config_ps(struct ath10k *ar)
memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter));
ar_iter.ar = ar;
- ieee80211_iterate_active_interfaces_atomic(
- ar->hw, IEEE80211_IFACE_ITER_NORMAL,
- ath10k_ps_iter, &ar_iter);
+ ieee80211_iterate_active_interfaces(ar->hw, IEEE80211_IFACE_ITER_NORMAL,
+ ath10k_ps_iter, &ar_iter);
if (ar_iter.ret)
ath10k_warn("failed to set ps config (%d)\n", ar_iter.ret);
@@ -2840,9 +2839,8 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
ar_iter.ar = ar;
mutex_lock(&ar->conf_mutex);
- ieee80211_iterate_active_interfaces_atomic(
- hw, IEEE80211_IFACE_ITER_NORMAL,
- ath10k_set_rts_iter, &ar_iter);
+ ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_NORMAL,
+ ath10k_set_rts_iter, &ar_iter);
mutex_unlock(&ar->conf_mutex);
return ar_iter.ret;
@@ -2881,9 +2879,8 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
ar_iter.ar = ar;
mutex_lock(&ar->conf_mutex);
- ieee80211_iterate_active_interfaces_atomic(
- hw, IEEE80211_IFACE_ITER_NORMAL,
- ath10k_set_frag_iter, &ar_iter);
+ ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_NORMAL,
+ ath10k_set_frag_iter, &ar_iter);
mutex_unlock(&ar->conf_mutex);
return ar_iter.ret;
--
1.7.9.5
^ permalink raw reply related
* [PATCH] rt2x00: rt2800lib: fix RF registers for RT5390/RT5392
From: Kevin Lo @ 2013-10-02 9:46 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, users
Update rf registers to use the same values that the MediaTek/Ralink
reference driver DPO_RT5572_LinuxSTA_2.6.1.3_20121022 uses.
References:
RF5390RegTable in chips/rt5390.c
RF5392RegTable in chips/rt5390.c
Tested on TP-Link TL-WN727N and D-Link DWA-140 Rev.b3 usb wifi dongles.
Signed-off-by: Kevin Lo <kevlo@kevlo.org>
---
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c
b/drivers/net/wireless/rt2x00/rt2800lib.c
index f414978..0bbd1b5 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -6449,7 +6449,7 @@ static void rt2800_init_rfcsr_5390(struct
rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
- rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
@@ -6487,7 +6487,7 @@ static void rt2800_init_rfcsr_5390(struct
rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 56, 0x22);
rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
- rt2800_rfcsr_write(rt2x00dev, 59, 0x63);
+ rt2800_rfcsr_write(rt2x00dev, 59, 0x8f);
rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
@@ -6507,7 +6507,6 @@ static void rt2800_init_rfcsr_5392(struct
rt2x00_dev *rt2x00dev)
rt2800_rf_init_calibration(rt2x00dev, 2);
rt2800_rfcsr_write(rt2x00dev, 1, 0x17);
- rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
^ permalink raw reply related
* Re: [PATCH] iwlwifi: pcie: fix merge damage
From: Johannes Berg @ 2013-10-02 9:41 UTC (permalink / raw)
To: linux-wireless; +Cc: linville
In-Reply-To: <1380531766-15384-1-git-send-email-johannes@sipsolutions.net>
On Mon, 2013-09-30 at 11:02 +0200, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
>
> The merge b35c8097 seems to have lost commit eabc4ac5d,
> put the code back.
I'm rebasing my tree on -rc1, which actually includes the merge commit,
so it still makes sense for me to include this commit - I've done that
now. Sorry for the confusion.
johannes
^ permalink raw reply
* Re: iwlegacy: iwl4965 reload firmware issue.
From: Stanislaw Gruszka @ 2013-10-02 9:19 UTC (permalink / raw)
To: Matt Chen; +Cc: linux-wireless, kvoz123
In-Reply-To: <CALx5=V_voRtb_e=9BFhNmt7rLO4v5iQKdZ0NCyZATtYCOUh7JA@mail.gmail.com>
On Tue, Oct 01, 2013 at 04:17:44PM +0800, Matt Chen wrote:
> The restart path is through il_irq_handle_error(il). My question is if
> this is a firmware issue, driver issue or hardware issue ?
Most likely driver issue, microcode error usually mean that driver provide
wrong values to the firmware or differently abuse firmware work.
Stanislaw
^ permalink raw reply
* Re: [PATCH] rt2x00_pci: Fix interrupt handler name (visible at /proc/interrupts)
From: Stanislaw Gruszka @ 2013-10-02 9:16 UTC (permalink / raw)
To: Kirill Tkhai; +Cc: linux-wireless, ivdoorn, gwingerde, helmut.schaa
In-Reply-To: <459361380660046@web2g.yandex.ru>
On Wed, Oct 02, 2013 at 12:40:46AM +0400, Kirill Tkhai wrote:
> Currently driver name is wrong. PCI device address is visible at
> /proc/interrupts instead of the name:
>
> 43: 124 0 0 0 PCI-MSI-edge rtsx_pci
> 44: 384 0 0 0 PCI-MSI-edge snd_hda_intel
> 45: 25096 0 0 0 PCI-MSI-edge 0000:01:00.0
> ^^^^^^^^^^^^
>
> So, pass the right name. rt2x00_ops->name contains KBUILD_MODNAME
> and good for that, so pass it.
>
> Handler names will be "rt2500pci", "rt2500pci" etc.
Looks sane. I was afraid that is not possible to have two or more
interrupts with the same name, but that's not true.
Acked-by: Stanislaw Gruszka <sgruszka@redhat.com>
Stanislaw
^ permalink raw reply
* Re: NetworkManager not listing access points
From: Johannes Berg @ 2013-10-02 9:08 UTC (permalink / raw)
To: Detlev Casanova; +Cc: Dan Williams, linux-wireless, laurent.pinchart
In-Reply-To: <3913713.WUui18VufC@naboo>
On Sun, 2013-09-29 at 21:29 +0200, Detlev Casanova wrote:
> > So I'm not sure what's going on here, but I don't think NetworkManager
> > is the issue; it's likely in the supplicant's scanning code or in the
> > driver itself. NetworkManager asks the supplicant to scan with both the
> > wildcard SSID and any hidden-tagged SSID, and the wildcard SSID should
> > ensure that all available APs are found.
>
> Yes and the problem is most likely to be in the driver because it doesn't
> occur before commit 0172bb75073e11a5aa9d8a953bdaefb8709f00c8 ("cfg80211: use
> DS or HT operation IEs to determine BSS channel")
Does it work on a newer kernel if you revert that commit? I really see
nothing wrong with that commit ...
Failing all else, since I can't reproduce the issue, can you please
compare the output of "iw list" before and after the failure (on the
failing kernel)? Maybe all channels are marked disabled or something?
But that really should've been the same behaviour before the patch too.
Also, tracing would be good (trace-cmd record -e cfg80211 -e mac80211,
compress trace.dat and send it to me)
johannes
^ permalink raw reply
* cfg80211/mac80211 merging done
From: Johannes Berg @ 2013-10-02 9:06 UTC (permalink / raw)
To: linux-wireless
Since I was travelling and then got sick during/after, it took me a
quite a while to get through my email.
I believe I've now gone through everything and merged or replied to
everything. If you expected a reply on a patch something and I haven't
gotten to it until now, I probably lost it so you should resend or ping
me.
johannes
^ permalink raw reply
* Re: [PATCH V4] cfg80211: vlan priority handling in WMM
From: Johannes Berg @ 2013-10-02 9:05 UTC (permalink / raw)
To: cedric.voncken; +Cc: linux-wireless
In-Reply-To: <1377518692-30084-1-git-send-email-cedric.voncken@acksys.fr>
On Mon, 2013-08-26 at 14:04 +0200, cedric.voncken@acksys.fr wrote:
> From: cedric Voncken <cedric.voncken@acksys.fr>
>
> If the VLAN tci is set in skb->vlan_tci use the priority field to determine the WMM priority.
Applied, with a linebreak in that commit log. Your (unnecessary) resend
of this also didn't even apply because it was line-wrapped in the patch.
johannes
^ permalink raw reply
* Re: [PATCH] nl80211: Provide per channel maximum regulatory transmit power
From: Helmut Schaa @ 2013-10-02 9:04 UTC (permalink / raw)
To: Johannes Berg, Jouni Malinen; +Cc: linux-wireless
In-Reply-To: <1380703470.13329.1.camel@jlt4.sipsolutions.net>
On Wed, Oct 2, 2013 at 10:44 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Wed, 2013-10-02 at 09:43 +0200, Helmut Schaa wrote:
>> In some cases its not only required to know the maximum transmit power
>> the hw is capable of. Instead, userspace (hostapd) might want to know
>> the maximum transmit power as defined in the current regulatory domain
>> (for example for 802.11d country IEs).
>
> Why wouldn't it use (the equivalent of) "iw reg get" for that?
Might be the more sane approach.
I noticed that hostapd generates 11d IEs based on the channel list it
reads from the kernel.
Thus restricting STAs to the max tx power the hw is capable of. Just
adding the max regulatory
tx power looked like an easy solution :)
Jouni, would you be ok with using the kernels regulatory domain for
11d IEs in hostapd?
Thanks,
Helmut
^ permalink raw reply
* [PATCH v2 4/4] ath10k: remove num_sends_allowed
From: Michal Kazior @ 2013-10-02 9:03 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1380704621-4670-1-git-send-email-michal.kazior@tieto.com>
The value provided by num_sends_allowed is now
derived from CE source ringbuffer state.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
drivers/net/wireless/ath/ath10k/ce.c | 17 ++++++++++++++++-
drivers/net/wireless/ath/ath10k/ce.h | 1 +
drivers/net/wireless/ath/ath10k/pci.c | 21 +--------------------
drivers/net/wireless/ath/ath10k/pci.h | 3 ---
4 files changed, 18 insertions(+), 24 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 9e6daa9..e46951b 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -283,7 +283,7 @@ static int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
if (unlikely(CE_RING_DELTA(nentries_mask,
write_index, sw_index - 1) <= 0)) {
- ret = -EIO;
+ ret = -ENOSR;
goto exit;
}
@@ -338,6 +338,21 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
return ret;
}
+int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe)
+{
+ struct ath10k *ar = pipe->ar;
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ int delta;
+
+ spin_lock_bh(&ar_pci->ce_lock);
+ delta = CE_RING_DELTA(pipe->src_ring->nentries_mask,
+ pipe->src_ring->write_index,
+ pipe->src_ring->sw_index - 1);
+ spin_unlock_bh(&ar_pci->ce_lock);
+
+ return delta;
+}
+
int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
void *per_recv_context,
u32 buffer)
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index 949b174..15d45b5 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -156,6 +156,7 @@ void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
void (*send_cb)(struct ath10k_ce_pipe *),
int disable_interrupts);
+int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe);
/*==================Recv=======================*/
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 4f6a978..f8d59c7 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -720,16 +720,6 @@ static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id,
"ath10k tx: data: ",
nbuf->data, nbuf->len);
- /* Make sure we have resources to handle this request */
- spin_lock_bh(&pipe_info->pipe_lock);
- if (!pipe_info->num_sends_allowed) {
- ath10k_warn("Pipe: %d is full\n", pipe_id);
- spin_unlock_bh(&pipe_info->pipe_lock);
- return -ENOSR;
- }
- pipe_info->num_sends_allowed--;
- spin_unlock_bh(&pipe_info->pipe_lock);
-
ret = ath10k_ce_send(ce_hdl, nbuf, skb_cb->paddr, len, transfer_id,
flags);
if (ret)
@@ -741,14 +731,7 @@ static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id,
static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- struct ath10k_pci_pipe *pipe_info = &(ar_pci->pipe_info[pipe]);
- int ret;
-
- spin_lock_bh(&pipe_info->pipe_lock);
- ret = pipe_info->num_sends_allowed;
- spin_unlock_bh(&pipe_info->pipe_lock);
-
- return ret;
+ return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl);
}
static void ath10k_pci_hif_dump_area(struct ath10k *ar)
@@ -863,7 +846,6 @@ static int ath10k_pci_start_ce(struct ath10k *ar)
ath10k_pci_ce_send_done,
disable_interrupts);
completions += attr->src_nentries;
- pipe_info->num_sends_allowed = attr->src_nentries - 1;
}
if (attr->dest_nentries) {
@@ -1033,7 +1015,6 @@ static void ath10k_pci_process_ce(struct ath10k *ar)
*/
spin_lock_bh(&compl->pipe_info->pipe_lock);
list_add_tail(&compl->list, &compl->pipe_info->compl_free);
- compl->pipe_info->num_sends_allowed += send_done;
spin_unlock_bh(&compl->pipe_info->pipe_lock);
}
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index 7c49f6f..52fb7b9 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -178,9 +178,6 @@ struct ath10k_pci_pipe {
/* List of free CE completion slots */
struct list_head compl_free;
- /* Limit the number of outstanding send requests. */
- int num_sends_allowed;
-
struct ath10k_pci *ar_pci;
struct tasklet_struct intr;
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 3/4] ath10k: remove ce_sendlist_send
From: Michal Kazior @ 2013-10-02 9:03 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1380704621-4670-1-git-send-email-michal.kazior@tieto.com>
It is completely pointless to keep this function
around. It doesn't do anything different than
ce_send except it introduces more overhead.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
drivers/net/wireless/ath/ath10k/ce.c | 34 ---------------------------------
drivers/net/wireless/ath/ath10k/ce.h | 15 ---------------
drivers/net/wireless/ath/ath10k/pci.c | 4 ++--
3 files changed, 2 insertions(+), 51 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 834e29e..9e6daa9 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -338,40 +338,6 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
return ret;
}
-int ath10k_ce_sendlist_send(struct ath10k_ce_pipe *ce_state,
- void *per_transfer_context,
- unsigned int transfer_id,
- u32 paddr, unsigned int nbytes,
- u32 flags)
-{
- struct ath10k_ce_ring *src_ring = ce_state->src_ring;
- struct ath10k *ar = ce_state->ar;
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- unsigned int nentries_mask = src_ring->nentries_mask;
- unsigned int sw_index;
- unsigned int write_index;
- int delta, ret = -ENOMEM;
-
- spin_lock_bh(&ar_pci->ce_lock);
-
- sw_index = src_ring->sw_index;
- write_index = src_ring->write_index;
-
- delta = CE_RING_DELTA(nentries_mask, write_index, sw_index - 1);
-
- if (delta >= 1) {
- ret = ath10k_ce_send_nolock(ce_state, per_transfer_context,
- paddr, nbytes,
- transfer_id, flags);
- if (ret)
- ath10k_warn("CE send failed: %d\n", ret);
- }
-
- spin_unlock_bh(&ar_pci->ce_lock);
-
- return ret;
-}
-
int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
void *per_recv_context,
u32 buffer)
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index aec8028..949b174 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -156,21 +156,6 @@ void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
void (*send_cb)(struct ath10k_ce_pipe *),
int disable_interrupts);
-/*
- * Queue a "sendlist" of buffers to be sent using gather to a single
- * anonymous destination buffer
- * ce - which copy engine to use
- * sendlist - list of simple buffers to send using gather
- * transfer_id - arbitrary ID; reflected to destination
- * Returns 0 on success; otherwise an error status.
- *
- * Implemenation note: Pushes multiple buffers with Gather to Source ring.
- */
-int ath10k_ce_sendlist_send(struct ath10k_ce_pipe *ce_state,
- void *per_transfer_context,
- unsigned int transfer_id,
- u32 paddr, unsigned int nbytes,
- u32 flags);
/*==================Recv=======================*/
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index dff23d9..4f6a978 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -730,8 +730,8 @@ static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id,
pipe_info->num_sends_allowed--;
spin_unlock_bh(&pipe_info->pipe_lock);
- ret = ath10k_ce_sendlist_send(ce_hdl, nbuf, transfer_id,
- skb_cb->paddr, len, flags);
+ ret = ath10k_ce_send(ce_hdl, nbuf, skb_cb->paddr, len, transfer_id,
+ flags);
if (ret)
ath10k_warn("CE send failed: %p\n", nbuf);
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 2/4] ath10k: split vdev_id calculation from tx function
From: Michal Kazior @ 2013-10-02 9:03 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1380704621-4670-1-git-send-email-michal.kazior@tieto.com>
Tidy up ath10k_tx().
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
drivers/net/wireless/ath/ath10k/mac.c | 25 +++++++++++++++----------
1 file changed, 15 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 7415a60..4b7c949 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1421,6 +1421,19 @@ static u8 ath10k_tx_h_get_tid(struct ieee80211_hdr *hdr)
return ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
}
+static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar,
+ struct ieee80211_tx_info *info)
+{
+ if (info->control.vif)
+ return ath10k_vif_to_arvif(info->control.vif)->vdev_id;
+
+ if (ar->monitor_enabled)
+ return ar->monitor_vdev_id;
+
+ ath10k_warn("could not resolve vdev id\n");
+ return 0;
+}
+
/*
* Frames sent to the FW have to be in "Native Wifi" format.
* Strip the QoS field from the 802.11 header.
@@ -1785,16 +1798,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ath10k *ar = hw->priv;
- struct ath10k_vif *arvif = NULL;
- u32 vdev_id = 0;
- u8 tid;
-
- if (info->control.vif) {
- arvif = ath10k_vif_to_arvif(info->control.vif);
- vdev_id = arvif->vdev_id;
- } else if (ar->monitor_enabled) {
- vdev_id = ar->monitor_vdev_id;
- }
+ u8 tid, vdev_id;
/* We should disable CCK RATE due to P2P */
if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
@@ -1803,6 +1807,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
/* we must calculate tid before we apply qos workaround
* as we'd lose the qos control field */
tid = ath10k_tx_h_get_tid(hdr);
+ vdev_id = ath10k_tx_h_get_vdev_id(ar, info);
/* it makes no sense to process injected frames like that */
if (info->control.vif &&
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 1/4] ath10k: split tid calculation from tx function
From: Michal Kazior @ 2013-10-02 9:03 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1380704621-4670-1-git-send-email-michal.kazior@tieto.com>
Tidy up ath10k_tx().
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
drivers/net/wireless/ath/ath10k/mac.c | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 8684e03..7415a60 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1407,6 +1407,20 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
/* TX handlers */
/***************/
+static u8 ath10k_tx_h_get_tid(struct ieee80211_hdr *hdr)
+{
+ if (ieee80211_is_mgmt(hdr->frame_control))
+ return HTT_DATA_TX_EXT_TID_MGMT;
+
+ if (!ieee80211_is_data_qos(hdr->frame_control))
+ return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
+
+ if (!is_unicast_ether_addr(ieee80211_get_DA(hdr)))
+ return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
+
+ return ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
/*
* Frames sent to the FW have to be in "Native Wifi" format.
* Strip the QoS field from the 802.11 header.
@@ -1788,14 +1802,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
/* we must calculate tid before we apply qos workaround
* as we'd lose the qos control field */
- tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
- if (ieee80211_is_mgmt(hdr->frame_control)) {
- tid = HTT_DATA_TX_EXT_TID_MGMT;
- } else if (ieee80211_is_data_qos(hdr->frame_control) &&
- is_unicast_ether_addr(ieee80211_get_DA(hdr))) {
- u8 *qc = ieee80211_get_qos_ctl(hdr);
- tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
- }
+ tid = ath10k_tx_h_get_tid(hdr);
/* it makes no sense to process injected frames like that */
if (info->control.vif &&
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 0/4] ath10k: clean ups
From: Michal Kazior @ 2013-10-02 9:03 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1380292706-3609-1-git-send-email-michal.kazior@tieto.com>
Hi,
First two patches are non-functional changes.
The latter two should remove some overhead from TX
path and CE processing. Nothing extraordinary.
PATCH v2:
* add commit messages for patch #1 and #2 (Kalle)
Michal Kazior (4):
ath10k: split tid calculation from tx function
ath10k: split vdev_id calculation from tx function
ath10k: remove ce_sendlist_send
ath10k: remove num_sends_allowed
drivers/net/wireless/ath/ath10k/ce.c | 35 ++++++------------------
drivers/net/wireless/ath/ath10k/ce.h | 16 +----------
drivers/net/wireless/ath/ath10k/mac.c | 48 ++++++++++++++++++++-------------
drivers/net/wireless/ath/ath10k/pci.c | 25 +++--------------
drivers/net/wireless/ath/ath10k/pci.h | 3 ---
5 files changed, 42 insertions(+), 85 deletions(-)
--
1.7.9.5
^ permalink raw reply
* Re: [PATCH] cfg80211: Pass station supported channel and oper class info to kernel
From: Johannes Berg @ 2013-10-02 9:00 UTC (permalink / raw)
To: Sunil Dutt; +Cc: linux-wireless, j
In-Reply-To: <1377582278-3768-1-git-send-email-c_duttus@qti.qualcomm.com>
On Tue, 2013-08-27 at 11:14 +0530, Sunil Dutt wrote:
> + if (info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]) {
> + params->supported_channels =
> + nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
> + params->supported_channels_len =
> + nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
It seems you should validate that the length is even, and at least 2?
> + if (info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]) {
> + params->supported_oper_classes =
> + nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
> + params->supported_oper_classes_len =
> + nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
Similarly here (with different rules)
Does this even make sense in set_station() rather than only
new_station()?
johannes
^ permalink raw reply
* Re: [PATCH] mac80211: allow mgmt frame transmission on DFS channels
From: Johannes Berg @ 2013-10-02 8:55 UTC (permalink / raw)
To: Lorenzo Bianconi; +Cc: linville, simon.wunderlich, linux-wireless
In-Reply-To: <1380545557-25103-1-git-send-email-lorenzo.bianconi83@gmail.com>
On Mon, 2013-09-30 at 14:52 +0200, Lorenzo Bianconi wrote:
> Allow management frame injection on DFS channels if the channel has been CAC
> checked and is available
> +++ b/net/mac80211/tx.c
> @@ -1694,8 +1694,10 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
> * radar detection by itself. We can do that later by adding a
> * monitor flag interfaces used for AP support.
> */
> - if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
> - IEEE80211_CHAN_PASSIVE_SCAN)))
> + if (((chan->flags & (IEEE80211_CHAN_PASSIVE_SCAN |
> + IEEE80211_CHAN_NO_IBSS))) ||
> + ((chan->flags & IEEE80211_CHAN_RADAR) &&
> + chan->dfs_state != NL80211_DFS_AVAILABLE))
This would be the only place where mac80211 is accessing
chan->dfs_state, does that make sense? Why is it not needed elsewhere?
johannes
^ permalink raw reply
* Re: [PATCH v2 4/5] {nl,cfg,mac}80211: finalizing mesh channel switching
From: Johannes Berg @ 2013-10-02 8:50 UTC (permalink / raw)
To: Chun-Yeow Yeoh; +Cc: linux-wireless, linville, devel, distro11s
In-Reply-To: <1380700964-844-5-git-send-email-yeohchunyeow@cozybit.com>
On Wed, 2013-10-02 at 01:02 -0700, Chun-Yeow Yeoh wrote:
> Finalizing the required procedures for channel switching completion based
> on the procedures defined in the IEEE Std 802.11-2012 section 10.9.8.4.3:
> * Add the function for updating the beacon and probe response frames
> with CSA and MCSP elements during the period of switching to the new
> channel.
> * The ifmsh->csa_settings is set to NULL and the CSA and MCSP elements
> will then be removed from the beacon or probe response frames once the
> new channel is switched to.
>
> Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
> ---
> v2: fix typo mistake, commit message and return value.
> use spinlock to protect csa_settings (Johannes Berg)
Is the spinlock really the best idea? It seems you could just use RCU
instead and avoid the extra lock? It's not exactly a hotpath, but the
paths that are assigning this should be locked already (I'd hope,
otherwise there might be more races) and the reader could be RCU.
johannes
^ permalink raw reply
* Re: [PATCH v2 5/5] mac80211: process mesh channel switching using beacon
From: Johannes Berg @ 2013-10-02 8:47 UTC (permalink / raw)
To: Chun-Yeow Yeoh; +Cc: linux-wireless, linville, devel, distro11s
In-Reply-To: <1380700964-844-6-git-send-email-yeohchunyeow@cozybit.com>
On Wed, 2013-10-02 at 01:02 -0700, Chun-Yeow Yeoh wrote:
> struct cfg80211_csa_settings {
> struct cfg80211_chan_def chandef;
> @@ -695,7 +697,9 @@ struct cfg80211_csa_settings {
> struct cfg80211_beacon_data beacon_after;
> bool radar_required;
> bool block_tx;
> + u8 mode;
> u8 count;
> + u8 ttl;
> };
You certainly meant well to reuse the structs, but that doesn't make
sense. This struct is used for the cfg80211/driver (cfg80211/mac80211)
API, so adding these parameters to it makes no sense at all. It seems
you'd need a new structure that's internal to mac80211 for the function
argument.
I'd also prefer to do the refactoring in a separate patch.
johannes
^ permalink raw reply
* Re: [PATCH] nl80211: Provide per channel maximum regulatory transmit power
From: Johannes Berg @ 2013-10-02 8:44 UTC (permalink / raw)
To: Helmut Schaa; +Cc: linux-wireless
In-Reply-To: <1380699789-3765-1-git-send-email-helmut.schaa@googlemail.com>
On Wed, 2013-10-02 at 09:43 +0200, Helmut Schaa wrote:
> In some cases its not only required to know the maximum transmit power
> the hw is capable of. Instead, userspace (hostapd) might want to know
> the maximum transmit power as defined in the current regulatory domain
> (for example for 802.11d country IEs).
Why wouldn't it use (the equivalent of) "iw reg get" for that?
> + if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_REG_TX_POWER,
> + DBM_TO_MBM(chan->max_reg_power)))
> + goto nla_put_failure;
This would have to go into the "if (large)" part because otherwise older
userspace can't read the info at all since it overflows the buffer.
johannes
^ permalink raw reply
* [PATCH v2 4/5] {nl,cfg,mac}80211: finalizing mesh channel switching
From: Chun-Yeow Yeoh @ 2013-10-02 8:02 UTC (permalink / raw)
To: linux-wireless; +Cc: johannes, linville, devel, distro11s, Chun-Yeow Yeoh
In-Reply-To: <1380700964-844-1-git-send-email-yeohchunyeow@cozybit.com>
Finalizing the required procedures for channel switching completion based
on the procedures defined in the IEEE Std 802.11-2012 section 10.9.8.4.3:
* Add the function for updating the beacon and probe response frames
with CSA and MCSP elements during the period of switching to the new
channel.
* The ifmsh->csa_settings is set to NULL and the CSA and MCSP elements
will then be removed from the beacon or probe response frames once the
new channel is switched to.
Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
---
v2: fix typo mistake, commit message and return value.
use spinlock to protect csa_settings (Johannes Berg)
net/mac80211/cfg.c | 7 +++++-
net/mac80211/ieee80211_i.h | 4 ++++
net/mac80211/mesh.c | 56 ++++++++++++++++++++++++++++++++++++++++++++
net/mac80211/rx.c | 5 +++-
net/mac80211/tx.c | 16 +++++++++++++
net/wireless/nl80211.c | 3 ++-
6 files changed, 88 insertions(+), 3 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 438c689..a0b41d7 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2887,6 +2887,11 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
case NL80211_IFTYPE_ADHOC:
ieee80211_ibss_finish_csa(sdata);
break;
+ case NL80211_IFTYPE_MESH_POINT:
+ err = ieee80211_mesh_finish_csa(sdata);
+ if (err < 0)
+ return;
+ break;
default:
WARN_ON(1);
return;
@@ -3005,7 +3010,7 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
params->chandef.chan->band)
return -EINVAL;
- err = ieee80211_send_action_csa(sdata, params);
+ err = ieee80211_mesh_csa_beacon(sdata, params, true);
if (err < 0)
return err;
break;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f50e471..175ec7e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1346,6 +1346,10 @@ void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata);
void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
+int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_csa_settings *csa_settings,
+ bool csa_action);
+int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata);
/* scan/BSS handling */
void ieee80211_scan_work(struct work_struct *work);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 7729679..93cfcb0 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -12,6 +12,7 @@
#include <asm/unaligned.h>
#include "ieee80211_i.h"
#include "mesh.h"
+#include "driver-ops.h"
static int mesh_allocated;
static struct kmem_cache *rm_cache;
@@ -956,6 +957,61 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
stype, mgmt, &elems, rx_status);
}
+int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ int ret = 0;
+
+ /* Remove the CSA and MCSP elements from the beacon */
+ spin_lock_bh(&ifmsh->csa_set_lock);
+ kfree(ifmsh->csa_settings);
+ ifmsh->csa_settings = NULL;
+ spin_unlock_bh(&ifmsh->csa_set_lock);
+ ret = ieee80211_mesh_rebuild_beacon(sdata);
+ if (ret)
+ return -EINVAL;
+
+ /* Reset the TTL value and Initiator flag */
+ ifmsh->chsw_init = false;
+ ifmsh->chsw_ttl = 0;
+
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+
+ mcsa_dbg(sdata, "complete switching to center freq %d MHz",
+ sdata->vif.bss_conf.chandef.chan->center_freq);
+ return 0;
+}
+
+int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_csa_settings *csa_settings,
+ bool csa_action)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct cfg80211_csa_settings *tmp_csa_settings;
+ int ret = 0;
+
+ if (csa_action)
+ ieee80211_send_action_csa(sdata, csa_settings);
+
+ tmp_csa_settings = kmalloc(sizeof(struct cfg80211_csa_settings),
+ GFP_ATOMIC);
+ if (!tmp_csa_settings)
+ return -ENOMEM;
+
+ spin_lock_bh(&ifmsh->csa_set_lock);
+ ifmsh->csa_settings = tmp_csa_settings;
+ memcpy(ifmsh->csa_settings, csa_settings,
+ sizeof(struct cfg80211_csa_settings));
+ spin_unlock_bh(&ifmsh->csa_set_lock);
+
+ ret = ieee80211_mesh_rebuild_beacon(sdata);
+ if (ret)
+ return -EINVAL;
+
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+ return 0;
+}
+
static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len)
{
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 8e908e1..0ba1fad 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2592,13 +2592,16 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
break;
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
- sdata->vif.type != NL80211_IFTYPE_ADHOC)
+ sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
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 if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
+ bssid = mgmt->sa;
else
break;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 4fcbf63..80b9a57 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2369,6 +2369,10 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
beacon_data = beacon->head;
beacon_data_len = beacon->head_len;
break;
+ case NL80211_IFTYPE_MESH_POINT:
+ beacon_data = beacon->head;
+ beacon_data_len = beacon->head_len;
+ break;
default:
return;
}
@@ -2425,6 +2429,15 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
beacon_data = beacon->head;
beacon_data_len = beacon->head_len;
+ } else if (vif->type == NL80211_IFTYPE_MESH_POINT) {
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+
+ beacon = rcu_dereference(ifmsh->beacon);
+ if (!beacon)
+ goto out;
+
+ beacon_data = beacon->head;
+ beacon_data_len = beacon->head_len;
} else {
WARN_ON(1);
goto out;
@@ -2530,6 +2543,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
if (!bcn)
goto out;
+ if (sdata->vif.csa_active)
+ ieee80211_update_csa(sdata, bcn);
+
if (ifmsh->sync_ops)
ifmsh->sync_ops->adjust_tbtt(
sdata);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 7bb5aca..be844d4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -10760,7 +10760,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
wdev->iftype != NL80211_IFTYPE_P2P_GO &&
- wdev->iftype != NL80211_IFTYPE_ADHOC))
+ wdev->iftype != NL80211_IFTYPE_ADHOC &&
+ wdev->iftype != NL80211_IFTYPE_MESH_POINT))
goto out;
wdev->channel = chandef->chan;
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 5/5] mac80211: process mesh channel switching using beacon
From: Chun-Yeow Yeoh @ 2013-10-02 8:02 UTC (permalink / raw)
To: linux-wireless; +Cc: johannes, linville, devel, distro11s, Chun-Yeow Yeoh
In-Reply-To: <1380700964-844-1-git-send-email-yeohchunyeow@cozybit.com>
Trigger the mesh channel switching procedure if the mesh STA
happens to miss the CSA action frame but able to receive the
beacon containing the CSA and MCSP elements from its peer
mesh STAs.
Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
---
v2: refactoring the ieee80211_parse_ch_switch_ie to reduce
parameters (Johannes Berg)
include/net/cfg80211.h | 4 ++
net/mac80211/ibss.c | 6 +--
net/mac80211/ieee80211_i.h | 8 ++-
net/mac80211/mesh.c | 128 +++++++++++++++++++++++++++++++++++++++++---
net/mac80211/mlme.c | 30 +++++------
net/mac80211/spectmgmt.c | 33 +++++++-----
6 files changed, 163 insertions(+), 46 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 47fdb1d..b278986 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -686,7 +686,9 @@ struct cfg80211_ap_settings {
* @beacon_after: beacon data to be used on the new channel
* @radar_required: whether radar detection is required on the new channel
* @block_tx: whether transmissions should be blocked while changing
+ * @mode: restriction on transmission until a channel switch
* @count: number of beacons until switch
+ * @ttl: mesh TTL related to channel switch
*/
struct cfg80211_csa_settings {
struct cfg80211_chan_def chandef;
@@ -695,7 +697,9 @@ struct cfg80211_csa_settings {
struct cfg80211_beacon_data beacon_after;
bool radar_required;
bool block_tx;
+ u8 mode;
u8 count;
+ u8 ttl;
};
/**
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 017e206..06a6a76 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -736,7 +736,6 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
enum nl80211_channel_type ch_type;
int err, num_chanctx;
u32 sta_flags;
- u8 mode;
if (sdata->vif.csa_active)
return true;
@@ -762,8 +761,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon,
ifibss->chandef.chan->band,
sta_flags, ifibss->bssid,
- ¶ms.count, &mode,
- ¶ms.chandef);
+ ¶ms);
/* can't switch to destination channel, fail */
if (err < 0)
@@ -859,7 +857,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
"received channel switch announcement to go to channel %d MHz\n",
params.chandef.chan->center_freq);
- params.block_tx = !!mode;
+ params.block_tx = !!params.mode;
ieee80211_ibss_csa_beacon(sdata, ¶ms);
sdata->csa_radar_required = params.radar_required;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 175ec7e..6c0b749 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1508,17 +1508,15 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
* %IEEE80211_STA_DISABLE_HT, %IEEE80211_STA_DISABLE_VHT,
* %IEEE80211_STA_DISABLE_40MHZ, %IEEE80211_STA_DISABLE_80P80MHZ,
* %IEEE80211_STA_DISABLE_160MHZ.
- * @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)
+ * @csa_ie: the output structure holding the required fields of chanswitch IEs
* 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);
+ u32 sta_flags, u8 *bssid,
+ struct cfg80211_csa_settings *csa_ie);
/* Suspend/resume and hw reconfiguration */
int ieee80211_reconfig(struct ieee80211_local *local);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 93cfcb0..428bf49 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -849,6 +849,120 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
ieee80211_configure_filter(local);
}
+static bool
+ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
+ struct ieee802_11_elems *elems, bool beacon)
+{
+ struct cfg80211_csa_settings params;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ struct ieee80211_chanctx *chanctx;
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
+ int err, num_chanctx;
+ u32 sta_flags;
+
+ if (sdata->vif.csa_active)
+ return true;
+
+ if (!ifmsh->mesh_id)
+ return false;
+
+ sta_flags = IEEE80211_STA_DISABLE_VHT;
+ switch (sdata->vif.bss_conf.chandef.width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ sta_flags |= IEEE80211_STA_DISABLE_HT;
+ 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, band,
+ sta_flags, sdata->vif.addr,
+ ¶ms);
+
+ if (err < 0)
+ return false;
+ if (err)
+ return false;
+
+ if (sdata->vif.bss_conf.chandef.chan->band !=
+ params.chandef.chan->band)
+ return false;
+
+ if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, ¶ms.chandef,
+ IEEE80211_CHAN_DISABLED)) {
+ sdata_info(sdata,
+ "mesh STA %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), aborting\n",
+ sdata->vif.addr,
+ params.chandef.chan->center_freq,
+ params.chandef.width,
+ params.chandef.center_freq1,
+ params.chandef.center_freq2);
+ return false;
+ }
+
+ err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
+ ¶ms.chandef);
+ if (err < 0)
+ return false;
+ if (err) {
+ params.radar_required = true;
+ /* TODO: DFS not (yet) supported */
+ return false;
+ }
+
+ rcu_read_lock();
+ chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+ if (!chanctx_conf)
+ goto failed_chswitch;
+
+ /* don't handle for multi-VIF cases */
+ chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
+ if (chanctx->refcount > 1)
+ goto failed_chswitch;
+
+ num_chanctx = 0;
+ list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
+ num_chanctx++;
+
+ if (num_chanctx > 1)
+ goto failed_chswitch;
+
+ rcu_read_unlock();
+
+ mcsa_dbg(sdata,
+ "received channel switch announcement to go to channel %d MHz\n",
+ params.chandef.chan->center_freq);
+
+ params.block_tx = params.mode & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
+ if (beacon)
+ ifmsh->chsw_ttl = params.ttl - 1;
+
+ if (ifmsh->chsw_ttl > 0)
+ ieee80211_mesh_csa_beacon(sdata, ¶ms, false);
+
+ 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;
+failed_chswitch:
+ rcu_read_unlock();
+ return false;
+}
+
static void
ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len)
@@ -955,6 +1069,9 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
if (ifmsh->sync_ops)
ifmsh->sync_ops->rx_bcn_presp(sdata,
stype, mgmt, &elems, rx_status);
+
+ if (!ifmsh->chsw_init)
+ ieee80211_mesh_process_chnswitch(sdata, &elems, true);
}
int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
@@ -1051,7 +1168,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee802_11_elems elems;
u16 pre_value;
- bool block_tx, fwd_csa = true;
+ bool fwd_csa = true;
size_t baselen;
u8 *pos, ttl;
@@ -1080,13 +1197,8 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
mcsa_dbg(sdata, "Failed to forward the CSA frame");
}
- /* block the Tx only after forwarding the CSA frame if required */
- block_tx = elems.mesh_chansw_params_ie->mesh_flags &
- WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
- if (block_tx)
- ieee80211_stop_queues_by_reason(&sdata->local->hw,
- IEEE80211_MAX_QUEUE_MAP,
- IEEE80211_QUEUE_STOP_REASON_CSA);
+ if (!ieee80211_mesh_process_chnswitch(sdata, &elems, false))
+ mcsa_dbg(sdata, "Failed to process CSA action frame");
}
static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9fce0f4..2e8297f 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -941,9 +941,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
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 = {};
+ struct cfg80211_csa_settings params;
int res;
sdata_assert_lock(sdata);
@@ -959,24 +957,24 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
return;
current_band = cbss->channel->band;
+ memset(¶ms, 0, sizeof(params));
res = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, current_band,
ifmgd->flags,
- ifmgd->associated->bssid, &count,
- &mode, &new_chandef);
+ ifmgd->associated->bssid, ¶ms);
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,
+ if (!cfg80211_chandef_usable(local->hw.wiphy, ¶ms.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_chandef.chan->center_freq,
- new_chandef.width, new_chandef.center_freq1,
- new_chandef.center_freq2);
+ params.chandef.chan->center_freq,
+ params.chandef.width, params.chandef.center_freq1,
+ params.chandef.center_freq2);
ieee80211_queue_work(&local->hw,
&ifmgd->csa_connection_drop_work);
return;
@@ -1009,9 +1007,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
}
mutex_unlock(&local->chanctx_mtx);
- local->csa_chandef = new_chandef;
+ local->csa_chandef = params.chandef;
- if (mode)
+ if (params.mode)
ieee80211_stop_queues_by_reason(&local->hw,
IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -1020,9 +1018,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
/* use driver's channel switch callback */
struct ieee80211_channel_switch ch_switch = {
.timestamp = timestamp,
- .block_tx = mode,
- .chandef = new_chandef,
- .count = count,
+ .block_tx = params.mode,
+ .chandef = params.chandef,
+ .count = params.count,
};
drv_channel_switch(local, &ch_switch);
@@ -1030,11 +1028,11 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
}
/* channel switch handled in software */
- if (count <= 1)
+ if (params.count <= 1)
ieee80211_queue_work(&local->hw, &ifmgd->chswitch_work);
else
mod_timer(&ifmgd->chswitch_timer,
- TU_TO_EXP_TIME(count * cbss->beacon_interval));
+ TU_TO_EXP_TIME(params.count * cbss->beacon_interval));
}
static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 921597e..ad0cded 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -24,8 +24,8 @@
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)
+ u32 sta_flags, u8 *bssid,
+ struct cfg80211_csa_settings *csa_ie)
{
enum ieee80211_band new_band;
int new_freq;
@@ -62,18 +62,24 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
return -EINVAL;
}
new_chan_no = elems->ext_chansw_ie->new_ch_num;
- *count = elems->ext_chansw_ie->count;
- *mode = elems->ext_chansw_ie->mode;
+ csa_ie->count = elems->ext_chansw_ie->count;
+ csa_ie->mode = elems->ext_chansw_ie->mode;
} else if (elems->ch_switch_ie) {
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;
+ csa_ie->count = elems->ch_switch_ie->count;
+ csa_ie->mode = elems->ch_switch_ie->mode;
} else {
/* nothing here we understand */
return 1;
}
+ /* Mesh Channel Switch Parameters Element */
+ if (elems->mesh_chansw_params_ie) {
+ csa_ie->ttl = elems->mesh_chansw_params_ie->mesh_ttl;
+ csa_ie->mode = elems->mesh_chansw_params_ie->mesh_flags;
+ }
+
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) {
@@ -103,25 +109,26 @@ int ieee80211_parse_ch_switch_ie(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(&csa_ie->chandef, new_chan,
NL80211_CHAN_HT20);
break;
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
- cfg80211_chandef_create(new_chandef, new_chan,
+ cfg80211_chandef_create(&csa_ie->chandef, new_chan,
NL80211_CHAN_HT40PLUS);
break;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
- cfg80211_chandef_create(new_chandef, new_chan,
+ cfg80211_chandef_create(&csa_ie->chandef, new_chan,
NL80211_CHAN_HT40MINUS);
break;
case -1:
- cfg80211_chandef_create(new_chandef, new_chan,
+ cfg80211_chandef_create(&csa_ie->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;
+ csa_ie->chandef.width =
+ sdata->vif.bss_conf.chandef.width;
break;
default:
break;
@@ -171,13 +178,13 @@ int ieee80211_parse_ch_switch_ie(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)) {
+ &csa_ie->chandef)) {
sdata_info(sdata,
"BSS %pM: CSA has inconsistent channel data, disconnecting\n",
bssid);
return -EINVAL;
}
- *new_chandef = new_vht_chandef;
+ csa_ie->chandef = new_vht_chandef;
}
return 0;
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 3/5] mac80211: add the CSA and MCSP elements in mesh beaconing
From: Chun-Yeow Yeoh @ 2013-10-02 8:02 UTC (permalink / raw)
To: linux-wireless; +Cc: johannes, linville, devel, distro11s, Chun-Yeow Yeoh
In-Reply-To: <1380700964-844-1-git-send-email-yeohchunyeow@cozybit.com>
Support the adding of CSA and MCSP elements while building the beacon
for mesh if necessary. This is defined in the IEEE Std 802.11-2012
section 10.9.8.4.3 that both CSA and MCSP elements must be included
in beacon and probe response frames until the intended channel
switch time.
Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
---
v2: introduce spinlock to protect csa_settings (Johannes Berg)
net/mac80211/ieee80211_i.h | 3 +++
net/mac80211/mesh.c | 38 ++++++++++++++++++++++++++++++++++++++
2 files changed, 41 insertions(+)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 829ff7e..f50e471 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -599,7 +599,10 @@ struct ieee80211_if_mesh {
int ps_peers_deep_sleep;
struct ps_data ps;
/* Channel Switching Support */
+ spinlock_t csa_set_lock;
+ struct cfg80211_csa_settings *csa_settings;
bool chsw_init;
+ u8 chsw_ttl;
u16 pre_value;
};
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 0a3ccaa..7729679 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -624,6 +624,10 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
head_len = hdr_len +
2 + /* NULL SSID */
+ /* Channel Switch Announcement */
+ 2 + sizeof(struct ieee80211_channel_sw_ie) +
+ /* Mesh Channel Swith Parameters */
+ 2 + sizeof(struct ieee80211_mesh_chansw_params_ie) +
2 + 8 + /* supported rates */
2 + 3; /* DS params */
tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
@@ -665,6 +669,38 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
*pos++ = WLAN_EID_SSID;
*pos++ = 0x0;
+ spin_lock_bh(&ifmsh->csa_set_lock);
+ if (ifmsh->csa_settings) {
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ __le16 pre_value;
+
+ pos = skb_put(skb, 13);
+ memset(pos, 0, 13);
+ *pos++ = WLAN_EID_CHANNEL_SWITCH;
+ *pos++ = 3;
+ *pos++ = 0x0;
+ *pos++ = ieee80211_frequency_to_channel(
+ ifmsh->csa_settings->chandef.chan->center_freq);
+ sdata->csa_counter_offset_beacon = hdr_len + 6;
+ *pos++ = ifmsh->csa_settings->count;
+ *pos++ = WLAN_EID_CHAN_SWITCH_PARAM;
+ *pos++ = 6;
+ if (ifmsh->chsw_init) {
+ *pos++ = ifmsh->mshcfg.dot11MeshTTL;
+ *pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
+ } else {
+ *pos++ = ifmsh->chsw_ttl;
+ }
+ *pos++ |= ifmsh->csa_settings->block_tx ?
+ WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
+ put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos);
+ pos += 2;
+ pre_value = cpu_to_le16(ifmsh->pre_value);
+ memcpy(pos, &pre_value, 2);
+ pos += 2;
+ }
+ spin_unlock_bh(&ifmsh->csa_set_lock);
+
if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
mesh_add_ds_params_ie(sdata, skb))
goto out_free;
@@ -942,6 +978,7 @@ static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
offset_ttl = (len < 42) ? 7 : 10;
*(pos + offset_ttl) -= 1;
*(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
+ sdata->u.mesh.chsw_ttl = *(pos + offset_ttl);
memcpy(mgmt_fwd, mgmt, len);
eth_broadcast_addr(mgmt_fwd->da);
@@ -1153,6 +1190,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
skb_queue_head_init(&ifmsh->ps.bc_buf);
spin_lock_init(&ifmsh->mesh_preq_queue_lock);
spin_lock_init(&ifmsh->sync_offset_lock);
+ spin_lock_init(&ifmsh->csa_set_lock);
RCU_INIT_POINTER(ifmsh->beacon, NULL);
sdata->vif.bss_conf.bssid = zero_addr;
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 2/5] {nl,cfg,mac}80211: enable the triggering of CSA frame in mesh
From: Chun-Yeow Yeoh @ 2013-10-02 8:02 UTC (permalink / raw)
To: linux-wireless; +Cc: johannes, linville, devel, distro11s, Chun-Yeow Yeoh
In-Reply-To: <1380700964-844-1-git-send-email-yeohchunyeow@cozybit.com>
Allow the triggering of CSA frame using mesh interface. The
rules are more or less same with IBSS, such as not allowed to
change between the band and channel width has to be same from
the previous mode. Also, move the ieee80211_send_action_csa
to a common space so that it can be re-used by mesh interface.
Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
---
v2: fix return value and others (Johannes Berg)
net/mac80211/cfg.c | 19 ++++++++++
net/mac80211/ibss.c | 54 ---------------------------
net/mac80211/ieee80211_i.h | 2 +
net/mac80211/util.c | 87 ++++++++++++++++++++++++++++++++++++++++++++
net/wireless/nl80211.c | 1 +
5 files changed, 109 insertions(+), 54 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index b455e72..438c689 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2907,6 +2907,7 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_chanctx *chanctx;
+ struct ieee80211_if_mesh *ifmsh;
int err, num_chanctx;
if (!list_empty(&local->roc_list) || local->scanning)
@@ -2990,6 +2991,24 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
if (err < 0)
return err;
break;
+ case NL80211_IFTYPE_MESH_POINT:
+ ifmsh = &sdata->u.mesh;
+
+ if (!ifmsh->mesh_id)
+ return -EINVAL;
+
+ if (params->chandef.width != sdata->vif.bss_conf.chandef.width)
+ return -EINVAL;
+
+ /* changes into another band are not supported */
+ if (sdata->vif.bss_conf.chandef.chan->band !=
+ params->chandef.chan->band)
+ return -EINVAL;
+
+ err = ieee80211_send_action_csa(sdata, params);
+ if (err < 0)
+ return err;
+ break;
default:
return -EOPNOTSUPP;
}
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 5ea9b3a..017e206 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -428,60 +428,6 @@ 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;
-}
-
int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
struct cfg80211_csa_settings *csa_settings)
{
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 7f13b65..829ff7e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1714,6 +1714,8 @@ void ieee80211_dfs_cac_timer(unsigned long data);
void ieee80211_dfs_cac_timer_work(struct work_struct *work);
void ieee80211_dfs_cac_cancel(struct ieee80211_local *local);
void ieee80211_dfs_radar_detected_work(struct work_struct *work);
+int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_csa_settings *csa_settings);
#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 133667c..5d12440 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2361,3 +2361,90 @@ u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
return ret;
}
+
+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_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;
+
+ if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
+ return -EOPNOTSUPP;
+
+ skb = dev_alloc_skb(local->tx_headroom + hdr_len +
+ 5 + /* channel switch announcement element */
+ 3 + /* secondary channel offset element */
+ 8); /* mesh channel switch parameters element */
+ if (!skb)
+ return -ENOMEM;
+
+ 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);
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
+ } else {
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+ 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;
+ }
+
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ __le16 pre_value;
+
+ skb_put(skb, 8);
+ *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; /* EID */
+ *pos++ = 6; /* IE length */
+ *pos++ = sdata->u.mesh.mshcfg.dot11MeshTTL; /* Mesh TTL */
+ *pos = 0x00; /* Mesh Flag: Tx Restrict, Initiator, Reason */
+ *pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
+ *pos++ |= csa_settings->block_tx ?
+ WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
+ put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */
+ pos += 2;
+ if (!ifmsh->pre_value)
+ ifmsh->pre_value = 1;
+ else
+ ifmsh->pre_value++;
+ pre_value = cpu_to_le16(ifmsh->pre_value);
+ memcpy(pos, &pre_value, 2); /* Precedence Value */
+ pos += 2;
+ ifmsh->chsw_init = true;
+ }
+
+ ieee80211_tx_skb(sdata, skb);
+ return 0;
+}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index da8de5b..7bb5aca 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5650,6 +5650,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
break;
case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
break;
default:
return -EOPNOTSUPP;
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 1/5] mac80211: process the CSA frame for mesh accordingly
From: Chun-Yeow Yeoh @ 2013-10-02 8:02 UTC (permalink / raw)
To: linux-wireless; +Cc: johannes, linville, devel, distro11s, Chun-Yeow Yeoh
In-Reply-To: <1380700964-844-1-git-send-email-yeohchunyeow@cozybit.com>
Process the CSA frame according to the procedures define in IEEE Std
802.11-2012 section 10.9.8.4.3 as follow:
* The mesh channel switch parameters element (MCSP) must be availabe.
* If the MCSP's TTL is 1, drop the frame but still process the CSA.
* If the MCSP's precedence value is less than or equal to the current
precedence value, drop the frame and do not process the CSA.
* The CSA frame is forwarded after TTL is decremented by 1 and the
initiator field is set to 0. Transmit restrict field and others
are maintained as is.
* No beacon or probe response frame are handled here.
Also, introduce the debug message used for mesh CSA purpose.
Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
---
v2: fix return value, typo and others (Johannes Berg)
include/linux/ieee80211.h | 20 +++++++++++
net/mac80211/Kconfig | 11 ++++++
net/mac80211/debug.h | 10 ++++++
net/mac80211/ieee80211_i.h | 4 +++
net/mac80211/mesh.c | 83 ++++++++++++++++++++++++++++++++++++++++++--
net/mac80211/util.c | 9 +++++
6 files changed, 134 insertions(+), 3 deletions(-)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 23a8877..f117427 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -696,6 +696,18 @@ struct ieee80211_sec_chan_offs_ie {
} __packed;
/**
+ * struct ieee80211_mesh_chansw_params_ie - mesh channel switch parameters IE
+ *
+ * This structure represents the "Mesh Channel Switch Paramters element"
+ */
+struct ieee80211_mesh_chansw_params_ie {
+ u8 mesh_ttl;
+ u8 mesh_flags;
+ __le16 mesh_reason;
+ __le16 mesh_pre_value;
+} __packed;
+
+/**
* struct ieee80211_wide_bw_chansw_ie - wide bandwidth channel switch IE
*/
struct ieee80211_wide_bw_chansw_ie {
@@ -750,6 +762,14 @@ enum mesh_config_capab_flags {
};
/**
+ * mesh channel switch parameters element's flag indicator
+ *
+ */
+#define WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT BIT(0)
+#define WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR BIT(1)
+#define WLAN_EID_CHAN_SWITCH_PARAM_REASON BIT(2)
+
+/**
* struct ieee80211_rann_ie
*
* This structure refers to "Root Announcement information element"
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 62535fe..bf1871e 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -258,6 +258,17 @@ config MAC80211_MESH_SYNC_DEBUG
Do not select this option.
+config MAC80211_MESH_CSA_DEBUG
+ bool "Verbose mesh channel switch debugging"
+ depends on MAC80211_DEBUG_MENU
+ depends on MAC80211_MESH
+ ---help---
+ Selecting this option causes mac80211 to print out very verbose mesh
+ channel switch debugging messages (when mac80211 is taking part in a
+ mesh network).
+
+ Do not select this option.
+
config MAC80211_MESH_PS_DEBUG
bool "Verbose mesh powersave debugging"
depends on MAC80211_DEBUG_MENU
diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h
index 4ccc5ed..493d680 100644
--- a/net/mac80211/debug.h
+++ b/net/mac80211/debug.h
@@ -44,6 +44,12 @@
#define MAC80211_MESH_SYNC_DEBUG 0
#endif
+#ifdef CONFIG_MAC80211_MESH_CSA_DEBUG
+#define MAC80211_MESH_CSA_DEBUG 1
+#else
+#define MAC80211_MESH_CSA_DEBUG 0
+#endif
+
#ifdef CONFIG_MAC80211_MESH_PS_DEBUG
#define MAC80211_MESH_PS_DEBUG 1
#else
@@ -157,6 +163,10 @@ do { \
_sdata_dbg(MAC80211_MESH_SYNC_DEBUG, \
sdata, fmt, ##__VA_ARGS__)
+#define mcsa_dbg(sdata, fmt, ...) \
+ _sdata_dbg(MAC80211_MESH_CSA_DEBUG, \
+ sdata, fmt, ##__VA_ARGS__)
+
#define mps_dbg(sdata, fmt, ...) \
_sdata_dbg(MAC80211_MESH_PS_DEBUG, \
sdata, fmt, ##__VA_ARGS__)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3a87c89..7f13b65 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -598,6 +598,9 @@ struct ieee80211_if_mesh {
int ps_peers_light_sleep;
int ps_peers_deep_sleep;
struct ps_data ps;
+ /* Channel Switching Support */
+ bool chsw_init;
+ u16 pre_value;
};
#ifdef CONFIG_MAC80211_MESH
@@ -1239,6 +1242,7 @@ struct ieee802_11_elems {
const struct ieee80211_timeout_interval_ie *timeout_int;
const u8 *opmode_notif;
const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
+ const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie;
/* length of them, respectively */
u8 ssid_len;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 707ac61..0a3ccaa 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -920,6 +920,82 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
stype, mgmt, &elems, rx_status);
}
+static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct ieee80211_mgmt *mgmt_fwd;
+ struct sk_buff *skb;
+ struct ieee80211_local *local = sdata->local;
+ u8 *pos = mgmt->u.action.u.chan_switch.variable;
+ size_t offset_ttl;
+
+ skb = dev_alloc_skb(local->tx_headroom + len);
+ if (!skb)
+ return -ENOMEM;
+ skb_reserve(skb, local->tx_headroom);
+ mgmt_fwd = (struct ieee80211_mgmt *) skb_put(skb, len);
+
+ /* offset_ttl is based on whether the secondary channel
+ * offset is available or not. Substract 1 from the mesh TTL
+ * and disable the initiator flag before forwarding.
+ */
+ offset_ttl = (len < 42) ? 7 : 10;
+ *(pos + offset_ttl) -= 1;
+ *(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
+
+ memcpy(mgmt_fwd, mgmt, len);
+ eth_broadcast_addr(mgmt_fwd->da);
+ memcpy(mgmt_fwd->sa, sdata->vif.addr, ETH_ALEN);
+ memcpy(mgmt_fwd->bssid, sdata->vif.addr, ETH_ALEN);
+
+ ieee80211_tx_skb(sdata, skb);
+ return 0;
+}
+
+static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct ieee802_11_elems elems;
+ u16 pre_value;
+ bool block_tx, fwd_csa = true;
+ size_t baselen;
+ u8 *pos, ttl;
+
+ if (mgmt->u.action.u.measurement.action_code !=
+ WLAN_ACTION_SPCT_CHL_SWITCH)
+ return;
+
+ pos = mgmt->u.action.u.chan_switch.variable;
+ baselen = offsetof(struct ieee80211_mgmt,
+ u.action.u.chan_switch.variable);
+ ieee802_11_parse_elems(pos, len - baselen, false, &elems);
+
+ ttl = elems.mesh_chansw_params_ie->mesh_ttl;
+ if (!--ttl)
+ fwd_csa = false;
+
+ pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
+ if (ifmsh->pre_value >= pre_value)
+ return;
+
+ ifmsh->pre_value = pre_value;
+
+ /* forward or re-broadcast the CSA frame */
+ if (fwd_csa) {
+ if (mesh_fwd_csa_frame(sdata, mgmt, len) < 0)
+ mcsa_dbg(sdata, "Failed to forward the CSA frame");
+ }
+
+ /* block the Tx only after forwarding the CSA frame if required */
+ block_tx = elems.mesh_chansw_params_ie->mesh_flags &
+ WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
+ if (block_tx)
+ ieee80211_stop_queues_by_reason(&sdata->local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_CSA);
+}
+
static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
size_t len,
@@ -939,6 +1015,9 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
if (mesh_action_is_path_sel(mgmt))
mesh_rx_path_sel_frame(sdata, mgmt, len);
break;
+ case WLAN_CATEGORY_SPECTRUM_MGMT:
+ mesh_rx_csa_frame(sdata, mgmt, len);
+ break;
}
}
@@ -1056,13 +1135,11 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
(unsigned long) sdata);
ifmsh->accepting_plinks = true;
- ifmsh->preq_id = 0;
- ifmsh->sn = 0;
- ifmsh->num_gates = 0;
atomic_set(&ifmsh->mpaths, 0);
mesh_rmc_init(sdata);
ifmsh->last_preq = jiffies;
ifmsh->next_perr = jiffies;
+ ifmsh->chsw_init = false;
/* Allocate all mesh structures when creating the first mesh interface. */
if (!mesh_allocated)
ieee80211s_init();
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 3c8283b..133667c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -743,6 +743,7 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
case WLAN_EID_TIMEOUT_INTERVAL:
case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
+ case WLAN_EID_CHAN_SWITCH_PARAM:
/*
* not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
* that if the content gets bigger it might be needed more than once
@@ -908,6 +909,14 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
}
elems->sec_chan_offs = (void *)pos;
break;
+ case WLAN_EID_CHAN_SWITCH_PARAM:
+ if (elen !=
+ sizeof(*elems->mesh_chansw_params_ie)) {
+ elem_parse_failed = true;
+ break;
+ }
+ elems->mesh_chansw_params_ie = (void *)pos;
+ break;
case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
if (!action ||
elen != sizeof(*elems->wide_bw_chansw_ie)) {
--
1.7.9.5
^ permalink raw reply related
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