* Re: [1/3] rsi: Fix memory leak in module unload
From: Kalle Valo @ 2016-11-17 6:44 UTC (permalink / raw)
To: Prameela Rani Garnepudi
Cc: linux-wireless, johannes.berg, hofrat, xypron.glpk,
prameela.garnepudi, Prameela Rani Garnepudi
In-Reply-To: <1476357946-15460-1-git-send-email-prameela.j04cs@gmail.com>
Prameela Rani Garnepudi <prameela.j04cs@gmail.com> wrote:
> Observed crash when module is unloaded if CONFIG_RSI_DEBUGSFS is not set.
> Fix: Debugfs entry removal moved inside CONFIG_RSI_DEBUGSFS flag in
> function rsi_mac80211_detach()
> Memory leak found and fixed for below structures in function rsi_mac80211_detach()
> * channel list for each supported band
> * rsi debugfs info
>
> Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
2 patches applied to wireless-drivers-next.git, thanks.
b022539db49a rsi: Fix memory leak in module unload
77364aae88d7 rsi: Host to device command frame vap_capabilites modified with new field vap status
--
https://patchwork.kernel.org/patch/9374919/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: brcmfmac: print name of connect status event
From: Kalle Valo @ 2016-11-17 6:45 UTC (permalink / raw)
To: Rafał Miłecki
Cc: Arend van Spriel, Franky Lin, Hante Meuleman,
Pieter-Paul Giesberts, Franky Lin, linux-wireless,
brcm80211-dev-list.pdl, netdev, linux-kernel,
Rafał Miłecki
In-Reply-To: <20161014074559.22962-1-zajec5@gmail.com>
Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
>
> This simplifies debugging. Format %s (%u) comes from similar debugging
> message in brcmf_fweh_event_worker.
>
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Patch applied to wireless-drivers-next.git, thanks.
e1c122d55f9e brcmfmac: print name of connect status event
--
https://patchwork.kernel.org/patch/9376147/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: p54: memset(0) whole array
From: Kalle Valo @ 2016-11-17 6:45 UTC (permalink / raw)
To: Jiri Slaby; +Cc: chunkeey, linux-kernel, Jiri Slaby, linux-wireless, netdev
In-Reply-To: <20161014092309.24113-1-jslaby@suse.cz>
Jiri Slaby <jslaby@suse.cz> wrote:
> gcc 7 complains:
> drivers/net/wireless/intersil/p54/fwio.c: In function 'p54_scan':
> drivers/net/wireless/intersil/p54/fwio.c:491:4: warning: 'memset' used with length equal to number of elements without multiplication by element size [-Wmemset-elt-size]
>
> Fix that by passing the correct size to memset.
>
> Signed-off-by: Jiri Slaby <jslaby@suse.cz>
> Cc: Christian Lamparter <chunkeey@googlemail.com>
> Cc: Kalle Valo <kvalo@codeaurora.org>
> Cc: linux-wireless@vger.kernel.org
> Cc: netdev@vger.kernel.org
> Acked-by: Christian Lamparter <chunkeey@googlemail.com>
Patch applied to wireless-drivers-next.git, thanks.
6f1758178820 p54: memset(0) whole array
--
https://patchwork.kernel.org/patch/9376333/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: wireless: fix bogus maybe-uninitialized warning
From: Kalle Valo @ 2016-11-17 6:46 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Kalle Valo, Stanislav Yakovlev, Jouni Malinen, Johannes Berg,
David S. Miller, linux-wireless, netdev, Arnd Bergmann,
linux-kernel
In-Reply-To: <20161024153918.2810634-2-arnd@arndb.de>
Arnd Bergmann <arnd@arndb.de> wrote:
> The hostap_80211_rx() function is supposed to set up the mac addresses
> for four possible cases, based on two bits of input data. For
> some reason, gcc decides that it's possible that none of the these
> four cases apply and the addresses remain uninitialized:
>
> drivers/net/wireless/intersil/hostap/hostap_80211_rx.c: In function ‘hostap_80211_rx’:
> arch/x86/include/asm/string_32.h:77:14: warning: ‘src’ may be used uninitialized in this function [-Wmaybe-uninitialized]
> drivers/net/wireless/intel/ipw2x00/libipw_rx.c: In function ‘libipw_rx’:
> arch/x86/include/asm/string_32.h:77:14: error: ‘dst’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
> arch/x86/include/asm/string_32.h:78:22: error: ‘*((void *)&dst+4)’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
>
> This warning is clearly nonsense, but changing the last case into
> 'default' makes it obvious to the compiler too, which avoids the
> warning and probably leads to better object code too.
>
> The same code is duplicated several times in the kernel, so this
> patch uses the same workaround for all copies. The exact configuration
> was hit only very rarely in randconfig builds and I only saw it
> in three drivers, but I assume that all of them are potentially
> affected, and it's better to keep the code consistent.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Patch applied to wireless-drivers-next.git, thanks.
10f3366b4d89 wireless: fix bogus maybe-uninitialized warning
--
https://patchwork.kernel.org/patch/9392385/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: [v2] cw1200: fix bogus maybe-uninitialized warning
From: Kalle Valo @ 2016-11-17 6:48 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Solomon Peachy, David Laight, Arnd Bergmann, Johannes Berg,
linux-wireless, netdev, linux-kernel
In-Reply-To: <20161025202121.1070879-1-arnd@arndb.de>
Arnd Bergmann <arnd@arndb.de> wrote:
> On x86, the cw1200 driver produces a rather silly warning about the
> possible use of the 'ret' variable without an initialization
> presumably after being confused by the architecture specific definition
> of WARN_ON:
>
> drivers/net/wireless/st/cw1200/wsm.c: In function ‘wsm_handle_rx’:
> drivers/net/wireless/st/cw1200/wsm.c:1457:9: error: ‘ret’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
>
> We have already checked that 'count' is larger than 0 here, so
> we know that 'ret' is initialized. Changing the 'for' loop
> into do/while also makes this clear to the compiler.
>
> Suggested-by: David Laight <David.Laight@ACULAB.COM>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Patch applied to wireless-drivers-next.git, thanks.
7fc1503c906f cw1200: fix bogus maybe-uninitialized warning
--
https://patchwork.kernel.org/patch/9395413/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: [net-next] rtlwifi: Use dev_kfree_skb_irq instead of kfree_skb
From: Kalle Valo @ 2016-11-17 6:48 UTC (permalink / raw)
To: Wei Yongjun; +Cc: Larry Finger, Chaoming Li, Wei Yongjun, linux-wireless
In-Reply-To: <1478011720-27363-1-git-send-email-weiyj.lk@gmail.com>
Wei Yongjun <weiyj.lk@gmail.com> wrote:
> From: Wei Yongjun <weiyongjun1@huawei.com>
>
> It is not allowed to call kfree_skb() from hardware interrupt
> context or with interrupts being disabled, spin_lock_irqsave()
> make sure always in irq disable context. So the kfree_skb()
> should be replaced with dev_kfree_skb_irq().
>
> This is detected by Coccinelle semantic patch.
>
> Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
Patch applied to wireless-drivers-next.git, thanks.
e49656147359 rtlwifi: Use dev_kfree_skb_irq instead of kfree_skb
--
https://patchwork.kernel.org/patch/9407493/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: ssb: Fix error routine when fallback SPROM fails
From: Kalle Valo @ 2016-11-17 6:49 UTC (permalink / raw)
To: Larry Finger; +Cc: devel, linux-wireless, Larry Finger, Stable
In-Reply-To: <20161105190857.19386-1-Larry.Finger@lwfinger.net>
Larry Finger <Larry.Finger@lwfinger.net> wrote:
> When there is a CRC error in the SPROM read from the device, the code
> attempts to handle a fallback SPROM. When this also fails, the driver
> returns zero rather than an error code.
>
> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
> Cc: Stable <stable@vger.kernel.org>
Patch applied to wireless-drivers-next.git, thanks.
8052d7245b60 ssb: Fix error routine when fallback SPROM fails
--
https://patchwork.kernel.org/patch/9413783/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: [RFC 1/2] ath9k: work around AR_CFG 0xdeadbeef chip hang
From: Sven Eckelmann @ 2016-11-17 7:23 UTC (permalink / raw)
To: Valo, Kalle
Cc: ath9k-devel@lists.ath9k.org, linux-wireless@vger.kernel.org,
ath9k-devel, Simon Wunderlich
In-Reply-To: <87wpg3mmc6.fsf@kamboji.qca.qualcomm.com>
[-- Attachment #1: Type: text/plain, Size: 1329 bytes --]
On Mittwoch, 16. November 2016 16:16:42 CET Valo, Kalle wrote:
> Sven Eckelmann <sven.eckelmann@open-mesh.com> writes:
>
> > From: Simon Wunderlich <simon.wunderlich@open-mesh.com>
> >
> > QCA 802.11n chips (especially AR9330/AR9340) sometimes end up in a state in
> > which a read of AR_CFG always returns 0xdeadbeef. This should not happen
> > when when the power_mode of the device is ATH9K_PM_AWAKE.
> >
> > This problem is not yet detected by any other workaround in ath9k. No way
> > is known to reproduce the problem easily.
> >
> > Signed-off-by: Simon Wunderlich <simon.wunderlich@open-mesh.com>
> > [sven.eckelmann@open-mesh.com: port to recent ath9k, add commit message]
> > Signed-off-by: Sven Eckelmann <sven.eckelmann@open-mesh.com>
>
> [...]
>
> > +void ath_hw_hang_work(struct work_struct *work)
> > +{
> > + struct ath_softc *sc = container_of(work, struct ath_softc,
> > + hw_hang_work.work);
> > +
> > + if (ath_hw_hang_deadbeef(sc))
> > + goto requeue_worker;
> > +
> > +requeue_worker:
> > + ieee80211_queue_delayed_work(sc->hw, &sc->hw_hang_work,
> > + msecs_to_jiffies(ATH_HANG_WORK_INTERVAL));
> > +}
>
> The goto doesn't make any sense, either me or the function is missing
> something :)
>
>
It is just for the next patch. And yes, could be done differently.
Kind regards,
Sven
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH V3] qtnfmac: announcement of new FullMAC driver for Quantenna chipsets
From: Johannes Berg @ 2016-11-17 7:54 UTC (permalink / raw)
To: IgorMitsyanko, linux-wireless
Cc: btherthala, hwang, smaksimenko, dlebed, Sergey Matyukevich,
Kamlesh Rath, Avinash Patil
In-Reply-To: <301c5abc-d28d-41dd-c7d6-4a7d7ec3681c@quantenna.com>
> > > +static int qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv
> > > *priv)
> > > +{
> > > + struct qtnf_shm_ipc_region __iomem *ipc_tx_reg;
> > > + struct qtnf_shm_ipc_region __iomem *ipc_rx_reg;
> > > + const struct qtnf_shm_ipc_int ipc_int = {
> > qtnf_ipc_gen_ep_int, priv };
> > >
> > > + const struct qtnf_shm_ipc_rx_callback rx_callback = {
> > > + qtnf_pcie_control_rx_cal
> > > lbac
> > k, priv };
> >
> > If those are const, why not also static? In fact, it seems they
> > really
> > should be, since they're registered below?
>
> Later qtnf_shm_ipc_init() will make a full copy of rx_callback (which
> actually only contains two pointers), it does not expect it to have
> static time of live, so no point in statically allocating it.
Ok. Nevertheless, marking it static might reduce binary size - as right
now there are two options for the compiler
1) emit a static variable anyway since it's const - no changes then
2) actually put it on the stack
a) from a static variable - extra memcpy()
b) initialised by code - extra initialisation code
Anyway, it doesn't really matter, just seemed strange to me :)
> The idea we used for flow synchronization is that all commands/events
> processing is serialized with RTNL mutex. Not very smart approach,
> but simple and in fact can be enough (there are not too much
> commands/notifications going on anyway). In the future it is possible
> to move to a more fine-grained locking.
Using the rtnl is probably fine, you've offloaded most things so can't
really expect much to happen on the host. You still might have problems
though - if you get a notification that the device disconnected, while
cfg80211 is already holding the RTNL to disconnect itself, the firmware
would think it's disconnected, the driver wouldn't have processed that
notification yet, and would try to disconnect.
That's just one possible race that we found in the past, and it needs
to be handled in the firmware anyway (basically: don't do anything bad
if asked to disconnect while not connected). :)
johannes
^ permalink raw reply
* [RFC v2 1/2] ath9k: work around AR_CFG 0xdeadbeef chip hang
From: Sven Eckelmann @ 2016-11-17 8:36 UTC (permalink / raw)
To: ath9k-devel; +Cc: linux-wireless, ath9k-devel, Simon Wunderlich, Sven Eckelmann
From: Simon Wunderlich <simon.wunderlich@open-mesh.com>
QCA 802.11n chips (especially AR9330/AR9340) sometimes end up in a state in
which a read of AR_CFG always returns 0xdeadbeef. This should not happen
when when the power_mode of the device is ATH9K_PM_AWAKE.
This problem is not yet detected by any other workaround in ath9k. No way
is known to reproduce the problem easily.
Signed-off-by: Simon Wunderlich <simon.wunderlich@open-mesh.com>
[sven.eckelmann@open-mesh.com: port to recent ath9k, add commit message]
Signed-off-by: Sven Eckelmann <sven.eckelmann@open-mesh.com>
---
v2:
- reduce amount of possible goto-raptor attacks by one (thanks Kalle Valo)
This was discussed 4 years ago on the OpenWrt mailing list. The most
relevant post is
https://lists.openwrt.org/pipermail/openwrt-devel/2012-September/016708.html
---
drivers/net/wireless/ath/ath9k/ath9k.h | 3 +++
drivers/net/wireless/ath/ath9k/debug.c | 1 +
drivers/net/wireless/ath/ath9k/debug.h | 1 +
drivers/net/wireless/ath/ath9k/init.c | 1 +
drivers/net/wireless/ath/ath9k/link.c | 31 +++++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath9k/main.c | 4 ++++
6 files changed, 41 insertions(+)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 26fc8ec..9c6fee7 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -710,11 +710,13 @@ void ath9k_csa_update(struct ath_softc *sc);
#define ATH_ANI_MAX_SKIP_COUNT 10
#define ATH_PAPRD_TIMEOUT 100 /* msecs */
#define ATH_PLL_WORK_INTERVAL 100
+#define ATH_HANG_WORK_INTERVAL 30000
void ath_tx_complete_poll_work(struct work_struct *work);
void ath_reset_work(struct work_struct *work);
bool ath_hw_check(struct ath_softc *sc);
void ath_hw_pll_work(struct work_struct *work);
+void ath_hw_hang_work(struct work_struct *work);
void ath_paprd_calibrate(struct work_struct *work);
void ath_ani_calibrate(unsigned long data);
void ath_start_ani(struct ath_softc *sc);
@@ -1014,6 +1016,7 @@ struct ath_softc {
#endif
struct delayed_work tx_complete_work;
struct delayed_work hw_pll_work;
+ struct delayed_work hw_hang_work;
struct timer_list sleep_timer;
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index c56e40f..608b370 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -767,6 +767,7 @@ static int read_file_reset(struct seq_file *file, void *data)
[RESET_TYPE_CALIBRATION] = "Calibration error",
[RESET_TX_DMA_ERROR] = "Tx DMA stop error",
[RESET_RX_DMA_ERROR] = "Rx DMA stop error",
+ [RESET_TYPE_DEADBEEF] = "deadbeef hang",
};
int i;
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index cd68c5f..0d77abbf6 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -52,6 +52,7 @@ enum ath_reset_type {
RESET_TYPE_CALIBRATION,
RESET_TX_DMA_ERROR,
RESET_RX_DMA_ERROR,
+ RESET_TYPE_DEADBEEF,
__RESET_TYPE_MAX
};
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 368d9b3..9bc7d1c 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -638,6 +638,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
INIT_WORK(&sc->hw_reset_work, ath_reset_work);
INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
+ INIT_DELAYED_WORK(&sc->hw_hang_work, ath_hw_hang_work);
ath9k_init_channel_context(sc);
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
index 5ad0fee..04195d5 100644
--- a/drivers/net/wireless/ath/ath9k/link.c
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -138,6 +138,37 @@ void ath_hw_pll_work(struct work_struct *work)
msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
}
+static bool ath_hw_hang_deadbeef(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ u32 reg;
+
+ /* check for stucked MAC */
+ ath9k_ps_wakeup(sc);
+ reg = REG_READ(sc->sc_ah, AR_CFG);
+ ath9k_ps_restore(sc);
+
+ if (reg != 0xdeadbeef)
+ return false;
+
+ ath_dbg(common, RESET,
+ "0xdeadbeef hang is detected. Schedule chip reset\n");
+ ath9k_queue_reset(sc, RESET_TYPE_DEADBEEF);
+
+ return true;
+}
+
+void ath_hw_hang_work(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc,
+ hw_hang_work.work);
+
+ ath_hw_hang_deadbeef(sc);
+
+ ieee80211_queue_delayed_work(sc->hw, &sc->hw_hang_work,
+ msecs_to_jiffies(ATH_HANG_WORK_INTERVAL));
+}
+
/*
* PA Pre-distortion.
*/
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index e9f32b5..4d3e216 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -183,6 +183,7 @@ static void __ath_cancel_work(struct ath_softc *sc)
cancel_work_sync(&sc->paprd_work);
cancel_delayed_work_sync(&sc->tx_complete_work);
cancel_delayed_work_sync(&sc->hw_pll_work);
+ cancel_delayed_work_sync(&sc->hw_hang_work);
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
if (ath9k_hw_mci_is_enabled(sc->sc_ah))
@@ -204,6 +205,9 @@ void ath_restart_work(struct ath_softc *sc)
ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
+ ieee80211_queue_delayed_work(sc->hw, &sc->hw_hang_work,
+ msecs_to_jiffies(ATH_HANG_WORK_INTERVAL));
+
ath_start_ani(sc);
}
--
2.10.2
^ permalink raw reply related
* [RFC v2 2/2] ath9k: Reset chip on potential deaf state
From: Sven Eckelmann @ 2016-11-17 8:36 UTC (permalink / raw)
To: ath9k-devel; +Cc: linux-wireless, ath9k-devel, Simon Wunderlich, Sven Eckelmann
In-Reply-To: <20161117083614.19188-1-sven.eckelmann@open-mesh.com>
From: Simon Wunderlich <simon.wunderlich@open-mesh.com>
The chip is switching seemingly random into a state which can be described
as "deaf". No or nearly no interrupts are generated anymore for incoming
packets. Existing links either break down after a while and new links will
not be established.
The driver doesn't know if there is no other device available or if it
ended up in an "deaf" state. Resetting the chip proactively avoids
permanent problems in case the chip really was in its "deaf" state but
maybe causes unnecessary resets in case it wasn't "deaf".
Signed-off-by: Simon Wunderlich <simon.wunderlich@open-mesh.com>
[sven.eckelmann@open-mesh.com: port to recent ath9k, add commit message]
Signed-off-by: Sven Eckelmann <sven.eckelmann@open-mesh.com>
---
v2:
- reduce amount of possible goto-raptor attacks by one (thanks Kalle Valo)
This problem was discovered in mesh setups. It was noticed that some nodes
were not able to see their neighbors (mostly after running for a while) -
even when those neighbors received data from them via IBSS. A simple `iw
dev wlan0 scan` fixed the problem for them. But the problem seems to
reappear after while(tm) in a large enough(tm) mesh.
This patch is a little bit obscure because it requires CONFIG_ATH9K_DEBUGFS
to actually work. But there still seems to be potential interest in
Freifunk communities or Freifunk meta-projects (e.g. freifunk-gluon). It is
currently not known if it helps them but publishing this to allow them to
test and play around with it will not hurt :)
---
drivers/net/wireless/ath/ath9k/ath9k.h | 3 +++
drivers/net/wireless/ath/ath9k/debug.c | 1 +
drivers/net/wireless/ath/ath9k/debug.h | 1 +
drivers/net/wireless/ath/ath9k/link.c | 48 +++++++++++++++++++++++++++++++++-
4 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 9c6fee7..3987ad5 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -996,6 +996,9 @@ struct ath_softc {
short nbcnvifs;
unsigned long ps_usecount;
+ unsigned long last_check_time;
+ u32 last_check_interrupts;
+
struct ath_rx rx;
struct ath_tx tx;
struct ath_beacon beacon;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 608b370..6d5c253 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -768,6 +768,7 @@ static int read_file_reset(struct seq_file *file, void *data)
[RESET_TX_DMA_ERROR] = "Tx DMA stop error",
[RESET_RX_DMA_ERROR] = "Rx DMA stop error",
[RESET_TYPE_DEADBEEF] = "deadbeef hang",
+ [RESET_TYPE_DEAF] = "deaf hang",
};
int i;
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 0d77abbf6..6f186bd 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -53,6 +53,7 @@ enum ath_reset_type {
RESET_TX_DMA_ERROR,
RESET_RX_DMA_ERROR,
RESET_TYPE_DEADBEEF,
+ RESET_TYPE_DEAF,
__RESET_TYPE_MAX
};
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
index 04195d5..ae99c02 100644
--- a/drivers/net/wireless/ath/ath9k/link.c
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -158,13 +158,59 @@ static bool ath_hw_hang_deadbeef(struct ath_softc *sc)
return true;
}
+static bool ath_hw_hang_deaf(struct ath_softc *sc)
+{
+#ifndef CONFIG_ATH9K_DEBUGFS
+ return false;
+#else
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ u32 interrupts, interrupt_per_s;
+ unsigned int interval;
+
+ /* get historic data */
+ interval = jiffies_to_msecs(jiffies - sc->last_check_time);
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
+ interrupts = sc->debug.stats.istats.rxlp;
+ else
+ interrupts = sc->debug.stats.istats.rxok;
+
+ interrupts -= sc->last_check_interrupts;
+
+ /* save current data */
+ sc->last_check_time = jiffies;
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
+ sc->last_check_interrupts = sc->debug.stats.istats.rxlp;
+ else
+ sc->last_check_interrupts = sc->debug.stats.istats.rxok;
+
+ /* sanity check, should be 30 seconds */
+ if (interval > 40000 || interval < 20000)
+ return false;
+
+ /* should be at least one interrupt per second */
+ interrupt_per_s = interrupts / (interval / 1000);
+ if (interrupt_per_s >= 1)
+ return false;
+
+ ath_dbg(common, RESET,
+ "RX deaf hang is detected. Schedule chip reset\n");
+ ath9k_queue_reset(sc, RESET_TYPE_DEAF);
+
+ return true;
+#endif
+}
+
void ath_hw_hang_work(struct work_struct *work)
{
struct ath_softc *sc = container_of(work, struct ath_softc,
hw_hang_work.work);
- ath_hw_hang_deadbeef(sc);
+ if (ath_hw_hang_deadbeef(sc))
+ goto requeue_worker;
+
+ ath_hw_hang_deaf(sc);
+requeue_worker:
ieee80211_queue_delayed_work(sc->hw, &sc->hw_hang_work,
msecs_to_jiffies(ATH_HANG_WORK_INTERVAL));
}
--
2.10.2
^ permalink raw reply related
* Re: [PATCH V3] qtnfmac: announcement of new FullMAC driver for Quantenna chipsets
From: Johannes Berg @ 2016-11-17 8:51 UTC (permalink / raw)
To: IgorMitsyanko, linux-wireless
In-Reply-To: <c6655668-f433-c784-0098-a94a61874e43@quantenna.com>
> > > It's probably worth having a discussion about this behaviour
> > > difference - not necessarily in the context of this driver
> > > submission though.
> >
> > Do you mean that default is to allow to dynamically allocate
> > resources (add_interface) for as much interfaces as memory allows,
> > but only use (allow to open) a limited number of them?
Correct, this is how mac80211 works.
> > This seems like unnecessary complication,
Well, I don't really know where this came from. I suspect some types of
mode switching cases could benefit from it, say (completely
constructed) your hardware supports either two AP or two clients, but
not AP+client - then to switch from 2xAP to 2xclient you'd have to
destroy one of the interfaces, since you can't mode-switch both at the
same time.
Also, interfaces that are down (should!) have no runtime impact on the
device whatsoever, so it's just a little bit more software complexity
to handle.
I think there may also be cases of cfg80211 doing partial interface
combination enforcement only on interfaces that are up.
> > I can see only one relevant comment in documentation to "struct
> > ieee80211_iface_combination" that does not clarify what should be
> > the behavior:
Agree, we never thought about it since for mac80211 it was always
obvious, and for other drivers the other way seemed obvious - I only
found out about it after the fact :)
I think the mode-switching I outlined above is a slight advantage to
the mac80211 scheme, so I wouldn't want to switch mac80211 to this
other scheme, risking that being seen as an API/ABI regression.
At the same time, having all drivers behave the same way seems somewhat
useful, but the consequence would be all drivers having to adopt the
mac80211 scheme. I can't say how difficult that would be - might be
more difficult than it seems since you couldn't statically allocate
your interface pointers etc. as you do now.
johannes
^ permalink raw reply
* [PATCH 2/2] nl80211: check NL80211_ATTR_SCHED_SCAN_INTERVAL only once
From: Arend van Spriel @ 2016-11-17 9:02 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1479373360-1398-1-git-send-email-arend.vanspriel@broadcom.com>
The presence of the NL80211_ATTR_SCHED_SCAN_INTERVAL attribute was
checked in nl80211_parse_sched_scan() and
nl80211_parse_sched_scan_plans() which might be a bit redundant
so removing one.
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
net/wireless/nl80211.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 24ab199..051cd5a 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6761,13 +6761,10 @@ static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
/*
* If scan plans are not specified,
- * %NL80211_ATTR_SCHED_SCAN_INTERVAL must be specified. In this
+ * %NL80211_ATTR_SCHED_SCAN_INTERVAL will be specified. In this
* case one scan plan will be set with the specified scan
* interval and infinite number of iterations.
*/
- if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
- return -EINVAL;
-
interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
if (!interval)
return -EINVAL;
--
1.9.1
^ permalink raw reply related
* [PATCH 1/2] cfg80211: get rid of name indirection trick for ieee80211_get_channel()
From: Arend van Spriel @ 2016-11-17 9:02 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel
The comment on the name indirection suggested an issue but turned out
to be untrue. Digging in older kernel version showed issue with ipw2x00
but that is no longer true so get rid on the name indirection.
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
include/net/cfg80211.h | 17 +++--------------
net/wireless/util.c | 5 ++---
2 files changed, 5 insertions(+), 17 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 2019310..ef42749 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3955,26 +3955,15 @@ static inline void *wdev_priv(struct wireless_dev *wdev)
*/
int ieee80211_frequency_to_channel(int freq);
-/*
- * Name indirection necessary because the ieee80211 code also has
- * a function named "ieee80211_get_channel", so if you include
- * cfg80211's header file you get cfg80211's version, if you try
- * to include both header files you'll (rightfully!) get a symbol
- * clash.
- */
-struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
- int freq);
/**
* ieee80211_get_channel - get channel struct from wiphy for specified frequency
+ *
* @wiphy: the struct wiphy to get the channel for
* @freq: the center frequency of the channel
+ *
* Return: The channel struct from @wiphy at @freq.
*/
-static inline struct ieee80211_channel *
-ieee80211_get_channel(struct wiphy *wiphy, int freq)
-{
- return __ieee80211_get_channel(wiphy, freq);
-}
+struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq);
/**
* ieee80211_get_response_rate - get basic rate for a given rate
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 88725f8..f717694 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -114,8 +114,7 @@ int ieee80211_frequency_to_channel(int freq)
}
EXPORT_SYMBOL(ieee80211_frequency_to_channel);
-struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
- int freq)
+struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq)
{
enum nl80211_band band;
struct ieee80211_supported_band *sband;
@@ -135,7 +134,7 @@ struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
return NULL;
}
-EXPORT_SYMBOL(__ieee80211_get_channel);
+EXPORT_SYMBOL(ieee80211_get_channel);
static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
enum nl80211_band band)
--
1.9.1
^ permalink raw reply related
* Re: [PATCH 2/5] rsi: Added rx filter frame
From: Kalle Valo @ 2016-11-17 10:58 UTC (permalink / raw)
To: Prameela Rani Garnepudi
Cc: linux-wireless, johannes.berg, hofrat, xypron.glpk,
prameela.garnepudi
In-Reply-To: <1479125812-2666-1-git-send-email-prameela.j04cs@gmail.com>
Prameela Rani Garnepudi <prameela.j04cs@gmail.com> writes:
> Filtering the rx frames in firmware after connection in station mode
> avoids the overhead of processing un-necessary frames. Hence rx filter
> frame is added which can be configured to device at suitable times.
>
> Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
A minor nitpick about the patch title. As I slept through most of my
english classes I don't know the correct terminology but the common
style is to use form "rsi: add foo", not "rsi: added foo".
> +/**
> + * This function sends a frame to filter the RX packets
> + *
> + * @param common Pointer to the driver private structure.
> + * @param rx_filter_word - Flags of filter packets
> + * @return 0 on success, -1 on failure.
> + */
> +int rsi_send_rx_filter_frame(struct rsi_common *common, u16 rx_filter_word)
Based on Documentation/kernel-documentation.rst this doesn't look to be
valid kernel-doc format. But AFAICS you got the format correct in patch
3.
Also this function uses negative error codes (as preferred), it's not
just -1 on failure. You should fix that in the comment (similar problems
also elsewhere in this patchset).
Personally I would not even bother adding kernel-docs for driver
internal functions. It's a lot of work to maintain them and still they
are quite often outdated, so people can't trust them and need to check
from the source anyway. But if you like them feel free to continue
adding them.
--
Kalle Valo
^ permalink raw reply
* Re: [PATCH 3/5] rsi: Added support for configuring tx power
From: Kalle Valo @ 2016-11-17 11:02 UTC (permalink / raw)
To: Prameela Rani Garnepudi
Cc: linux-wireless, johannes.berg, hofrat, xypron.glpk,
prameela.garnepudi
In-Reply-To: <1479125836-2722-1-git-send-email-prameela.j04cs@gmail.com>
Prameela Rani Garnepudi <prameela.j04cs@gmail.com> writes:
> TX power can be configured from iwconfig, iw or from mac80211 when
> regulatory changes are done. Hence support for configuring tx power
> to device is added. This can be done by sending RADIO_PARAMS_UPDATE
> command frame to device with upated tx power value.
>
> Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
[...]
> /* Send Frames Types */
> enum cmd_frame_type {
> - TX_DOT11_MGMT,
> - RESET_MAC_REQ,
> - RADIO_CAPABILITIES,
> - BB_PROG_VALUES_REQUEST,
> - RF_PROG_VALUES_REQUEST,
> - WAKEUP_SLEEP_REQUEST,
> - SCAN_REQUEST,
> - TSF_UPDATE,
> - PEER_NOTIFY,
> - BLOCK_HW_QUEUE,
> - SET_KEY_REQ,
> - AUTO_RATE_IND,
> - BOOTUP_PARAMS_REQUEST,
> - VAP_CAPABILITIES,
> - EEPROM_READ_TYPE ,
> - EEPROM_WRITE,
> - GPIO_PIN_CONFIG ,
> - SET_RX_FILTER,
> - AMPDU_IND,
> - STATS_REQUEST_FRAME,
> - BB_BUF_PROG_VALUES_REQ,
> - BBP_PROG_IN_TA,
> - BG_SCAN_PARAMS,
> - BG_SCAN_PROBE_REQ,
> - CW_MODE_REQ,
> - PER_CMD_PKT
> + TX_DOT11_MGMT = 0,
> + RESET_MAC_REQ, /* 0x1 */
> + RADIO_CAPABILITIES, /* 0x2 */
> + BB_PROG_VALUES_REQUEST, /* 0x3 */
> + RF_PROG_VALUES_REQUEST, /* 0x4 */
> + WAKEUP_SLEEP_REQUEST, /* 0x5 */
> + SCAN_REQUEST, /* 0x6 */
> + TSF_UPDATE, /* 0x7 */
> + PEER_NOTIFY, /* 0x8 */
> + BLOCK_HW_QUEUE, /* 0x9 */
> + SET_KEY_REQ, /* 0xA */
> + AUTO_RATE_IND, /* 0xB */
> + BOOTUP_PARAMS_REQUEST, /* 0xC */
> + VAP_CAPABILITIES, /* 0xD */
> + EEPROM_READ_TYPE, /* 0xE */
> + EEPROM_WRITE, /* 0xF */
> + GPIO_PIN_CONFIG, /* 0x10 */
> + SET_RX_FILTER, /* 0x11 */
> + AMPDU_IND, /* 0x12 */
> + STATS_REQUEST, /* 0x13 */
> + BB_BUF_PROG_VALUES_REQ, /* 0x14 */
> + BBP_PROG_IN_TA, /* 0x15 */
> + BG_SCAN_PARAMS, /* 0x16 */
> + BG_SCAN_PROBE_REQ, /* 0x17 */
> + CW_MODE_REQ, /* 0x18 */
> + PER_CMD_PKT, /* 0x19 */
> + DEV_SLEEP_REQUEST, /* 0x1A */
> + DEV_WAKEUP_CNF, /* 0x1B */
> + RF_LOOPBACK_REQ, /* 0x1C */
> + RF_LPBK_M3, /* 0x1D */
> + RF_RESET_FRAME, /* 0x1E */
> + LMAC_REG_OPS, /* 0x1F */
> + ANT_SEL_FRAME, /* 0x20 */
> + CONFIRM, /* 0x21 */
> + WLAN_DE_REGISTER, /* 0x22 */
> + DEBUG_FRAME, /* 0x23 */
> + HW_BMISS_HANDLE, /* 0x24 */
> + MULTICAST_ENABLE, /* 0x25 */
> + TX_MISC_IND, /* 0x26 */
> + VAP_DYNAMIC_UPDATE, /* 0x27 */
> + COMMON_DEV_CONFIG, /* 0x28 */
> + RADIO_PARAMS_UPDATE, /* 0x29 */
> + RADAR_REQUEST, /* 0x2A */
> + WOWLAN_CONFIG_PARAMS, /* 2B */
> + IAP_CONFIG, /* 0x2C */
> };
Adding the values for enums is a separate logical change and makes it
hard to see the real changes, so please do this in a separate patch.
But in overall your patches look now _much_ better, easy to review and
basically what I expect to see. Keep up the good work.
--
Kalle Valo
^ permalink raw reply
* Re: [4.9.0-rc5] AR9300 calibration problems with antenna selected
From: Kalle Valo @ 2016-11-17 11:09 UTC (permalink / raw)
To: Krzysztof Hałasa
Cc: QCA ath9k Development, linux-wireless, ath9k-devel, netdev,
linux-kernel
In-Reply-To: <m3wpg52hii.fsf@t19.piap.pl>
Krzysztof wrote:
> Hi,
>
> I recently tried to select a single antenna on AR9300 and it works for
> 30 seconds only. The subsequent calibration makes the RX signal level to
> drop from the usual -30/-40 dBm to -70/-80 dBm, and the transmission
> practically stops.
>
> With the attached patch it works, though selecting the antenna doesn't
> seem to have any visible effect, at least with "iw wlanX station dump"
> (perhaps it works for TX).
>
> I'm using ad-hoc mode:
>
> rmmod ath9k
> modprobe ath9k
> iw dev wlan0 set type ibss
> iw phy phyX set antenna 2
> ip link set up dev wlan0
> iw dev wlan0 set bitrates legacy-2.4 18
> iw dev wlan0 ibss join nameXXX freqYYY
> ip addr add ZZZ broadcast + dev wlan0
>
> The card in question is Mikrotik (Routerboard) R11e-2HPnD mPCIe adapter:
> AR9580 Wireless Network Adapter (rev 01), ID 168c:0033, subsystem
> 19b6:d016.
> ieee80211 phy0: Atheros AR9300 Rev:4 mem=0xc0f40000, irq=334
> https://routerboard.com/R11e-2HPnD
>
> Linux 4.9.0-rc5.
>
>
> Is there a better way?
>
> Signed-off-by: Krzysztof Halasa <khalasa@piap.pl>
>
> diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
> index e9f32b5..7f17e5d 100644
> --- a/drivers/net/wireless/ath/ath9k/main.c
> +++ b/drivers/net/wireless/ath/ath9k/main.c
> @@ -2245,7 +2245,7 @@ static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
> return 0;
>
> /* AR9100 runs into calibration issues if not all rx chains are enabled */
> - if (AR_SREV_9100(ah))
> + if (AR_SREV_9100(ah) || AR_SREV_9300(ah))
> ah->rxchainmask = 0x7;
> else
> ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant);
I'll assume this is an RFC patch. Please resubmit if this is the right
approach.
Patch set to RFC.
--
https://patchwork.kernel.org/patch/9429263/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: mwifiex: fix memory leak in mwifiex_save_hidden_ssid_channels()
From: Kalle Valo @ 2016-11-17 11:13 UTC (permalink / raw)
To: Ricky Liang
In-Reply-To: <1478662648-70698-1-git-send-email-jcliang@chromium.org>
Ricky Liang <jcliang@chromium.org> wrote:
> kmemleak reports memory leak in mwifiex_save_hidden_ssid_channels():
>
> unreferenced object 0xffffffc0a2914780 (size 192):
> comm "ksdioirqd/mmc2", pid 2004, jiffies 4307182506 (age 820.684s)
> hex dump (first 32 bytes):
> 00 06 47 49 4e 2d 32 67 01 03 c8 60 6c 03 01 40 ..GIN-2g...`l..@
> 07 10 54 57 20 34 04 1e 64 05 24 84 03 24 95 04 ..TW 4..d.$..$..
> backtrace:
> [<ffffffc0003375f4>] create_object+0x164/0x2b4
> [<ffffffc0008e3530>] kmemleak_alloc+0x50/0x88
> [<ffffffc000335120>] __kmalloc_track_caller+0x1bc/0x264
> [<ffffffc00030899c>] kmemdup+0x38/0x64
> [<ffffffbffc2311cc>] mwifiex_fill_new_bss_desc+0x3c/0x130 [mwifiex]
> [<ffffffbffc22ee9c>] mwifiex_save_curr_bcn+0x4ec/0x640 [mwifiex]
> [<ffffffbffc22f45c>] mwifiex_handle_event_ext_scan_report+0x1d4/0x268 [mwifiex]
> [<ffffffbffc2375d0>] mwifiex_process_sta_event+0x378/0x898 [mwifiex]
> [<ffffffbffc224dc8>] mwifiex_process_event+0x1a8/0x1e8 [mwifiex]
> [<ffffffbffc2228f0>] mwifiex_main_process+0x258/0x534 [mwifiex]
> [<ffffffbffc258858>] 0xffffffbffc258858
> [<ffffffc00071ee90>] process_sdio_pending_irqs+0xf8/0x160
> [<ffffffc00071efdc>] sdio_irq_thread+0x9c/0x1a4
> [<ffffffc000240d08>] kthread+0xf4/0x100
> [<ffffffc0002043fc>] ret_from_fork+0xc/0x50
> [<ffffffffffffffff>] 0xffffffffffffffff
>
> Signed-off-by: Ricky Liang <jcliang@chromium.org>
> Acked-by: Amitkumar Karwar <akarwar@marvell.com>
> Reviewed-by: Brian Norris <briannorris@chromium.org>
Patch applied to wireless-drivers-next.git, thanks.
5ff262229378 mwifiex: fix memory leak in mwifiex_save_hidden_ssid_channels()
--
https://patchwork.kernel.org/patch/9418433/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: mwifiex: printk() overflow with 32-byte SSIDs
From: Kalle Valo @ 2016-11-17 11:18 UTC (permalink / raw)
To: Brian Norris
Cc: Amitkumar Karwar, Nishant Sarmukadam, linux-kernel,
linux-wireless, Cathy Luo, security, stable, Brian Norris
In-Reply-To: <1478658504-31045-1-git-send-email-briannorris@chromium.org>
Brian Norris <briannorris@chromium.org> wrote:
> SSIDs aren't guaranteed to be 0-terminated. Let's cap the max length
> when we print them out.
>
> This can be easily noticed by connecting to a network with a 32-octet
> SSID:
>
> [ 3903.502925] mwifiex_pcie 0000:01:00.0: info: trying to associate to
> '0123456789abcdef0123456789abcdef <uninitialized mem>' bssid
> xx:xx:xx:xx:xx:xx
>
> Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver")
> Signed-off-by: Brian Norris <briannorris@chromium.org>
> Cc: <stable@vger.kernel.org>
> Acked-by: Amitkumar Karwar <akarwar@marvell.com>
Patch applied to wireless-drivers.git, thanks.
fcd2042e8d36 mwifiex: printk() overflow with 32-byte SSIDs
--
https://patchwork.kernel.org/patch/9418369/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: [1/2] mwifiex: fix corner case power save issue
From: Kalle Valo @ 2016-11-17 11:28 UTC (permalink / raw)
To: Amitkumar Karwar
Cc: linux-wireless, Cathy Luo, Nishant Sarmukadam, Amitkumar Karwar
In-Reply-To: <1477062948-8558-1-git-send-email-akarwar@marvell.com>
Amitkumar Karwar <akarwar@marvell.com> wrote:
> We may get SLEEP event from firmware even if TXDone for last Tx packet
> is still pending. In this case, we may end up accessing PCIe memory for
> handling TXDone after power save handshake is completed. This causes
> kernel crash with external abort.
>
> We will delay sending SLEEP confirm to firmware in
> this case to resolve the problem.
>
> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
> Tested-by: Brian Norris <briannorris@chromium.org>
> Reviewed-by: Brian Norris <briannorris@chromium.org>
Dropped per request from Amitkumar.
Patch set to Changes Requested.
--
https://patchwork.kernel.org/patch/9389485/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* [PATCH 1/5] nl80211: allow reporting RTT information in scan results
From: Arend van Spriel @ 2016-11-17 11:39 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1479382792-13131-1-git-send-email-arend.vanspriel@broadcom.com>
Add distance and its variance to the BSS structure so drivers
may provide RTT information for BSS instances found during
scanning.
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
include/net/cfg80211.h | 11 +++++++++++
include/uapi/linux/nl80211.h | 6 ++++++
net/wireless/nl80211.c | 8 ++++++++
net/wireless/scan.c | 2 ++
4 files changed, 27 insertions(+)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 2019310..d1217da 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1675,6 +1675,9 @@ enum cfg80211_signal_type {
* @scan_width: scan width that was used
* @signal: signal strength value, according to the wiphy's
* signal type
+ * @distance: distance to AP with %parent_bssid in centimeters. Zero
+ * value indicates this is undetermined.
+ * @var_distance: variance of %distance indicating accurracy.
* @boottime_ns: timestamp (CLOCK_BOOTTIME) when the information was
* received; should match the time when the frame was actually
* received by the device (not just by the host, in case it was
@@ -1691,6 +1694,8 @@ struct cfg80211_inform_bss {
struct ieee80211_channel *chan;
enum nl80211_bss_scan_width scan_width;
s32 signal;
+ u32 distance;
+ u32 var_distance;
u64 boottime_ns;
u64 parent_tsf;
u8 parent_bssid[ETH_ALEN] __aligned(2);
@@ -1737,6 +1742,9 @@ struct cfg80211_bss_ies {
* that holds the beacon data. @beacon_ies is still valid, of course, and
* points to the same data as hidden_beacon_bss->beacon_ies in that case.
* @signal: signal strength value (type depends on the wiphy's signal_type)
+ * @distance: distance to AP with %parent_bssid in centimeters. Zero
+ * value indicates this is undetermined.
+ * @var_distance: variance of %distance indicating accurracy.
* @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
*/
struct cfg80211_bss {
@@ -1756,6 +1764,9 @@ struct cfg80211_bss {
u8 bssid[ETH_ALEN];
+ u32 distance;
+ u32 var_distance;
+
u8 priv[0] __aligned(sizeof(void *));
};
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 259c9c7..7e935f6 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3651,6 +3651,10 @@ enum nl80211_bss_scan_width {
* @NL80211_BSS_PARENT_BSSID. (u64).
* @NL80211_BSS_PARENT_BSSID: the BSS according to which @NL80211_BSS_PARENT_TSF
* is set.
+ * @NL80211_BSS_DISTANCE: distance to AP with @NL80211_BSS_PARENT_BSSID in
+ * centimeters (u32).
+ * @NL80211_BSS_VARIANCE_DISTANCE: variance of @NL80211_BSS_DISTANCE value (u32).
+ *
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -3674,6 +3678,8 @@ enum nl80211_bss {
NL80211_BSS_PAD,
NL80211_BSS_PARENT_TSF,
NL80211_BSS_PARENT_BSSID,
+ NL80211_BSS_DISTANCE,
+ NL80211_BSS_VARIANCE_DISTANCE,
/* keep last */
__NL80211_BSS_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 24ab199..ffce566 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -7515,6 +7515,14 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
intbss->ts_boottime, NL80211_BSS_PAD))
goto nla_put_failure;
+ if (res->distance && nla_put_u32(msg, NL80211_BSS_DISTANCE,
+ res->distance))
+ goto nla_put_failure;
+
+ if (res->var_distance && nla_put_u32(msg, NL80211_BSS_VARIANCE_DISTANCE,
+ res->var_distance))
+ goto nla_put_failure;
+
switch (rdev->wiphy.signal_type) {
case CFG80211_SIGNAL_TYPE_MBM:
if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal))
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index b5bd58d..afda1f9 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -973,6 +973,8 @@ struct cfg80211_bss *
tmp.pub.signal = data->signal;
tmp.pub.beacon_interval = beacon_interval;
tmp.pub.capability = capability;
+ tmp.pub.distance = data->distance;
+ tmp.pub.var_distance = data->var_distance;
tmp.ts_boottime = data->boottime_ns;
/*
--
1.9.1
^ permalink raw reply related
* [PATCH 2/5] nl80211: add reporting of gscan capabilities
From: Arend van Spriel @ 2016-11-17 11:39 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel, Arend van Spriel
In-Reply-To: <1479382792-13131-1-git-send-email-arend.vanspriel@broadcom.com>
From: Arend van Spriel <arend@broadcom.com>
GScan is a scan offload feature used in recent Android releases. This
patch adds possibility for wireless device drivers to report their
capabilities and provide it to user-space.
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
include/net/cfg80211.h | 36 +++++++++++++++++++++++++++
include/uapi/linux/nl80211.h | 58 ++++++++++++++++++++++++++++++++++++++++++++
net/wireless/nl80211.c | 45 +++++++++++++++++++++++++++++++++-
3 files changed, 138 insertions(+), 1 deletion(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d1217da..c77bb08 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3372,6 +3372,40 @@ struct wiphy_iftype_ext_capab {
};
/**
+ * struct wiphy_gscan_caps - gscan capabilities of the device.
+ *
+ * @max_scan_cache_size: total space allocated for scan results (in bytes).
+ * @max_scan_buckets: maximum number of channel buckets.
+ * @max_ap_cache_per_scan: maximum number of APs that can be stored per scan.
+ * @max_rssi_sample_size: number of RSSI samples used for averaging RSSI.
+ * @max_scan_reporting_threshold: max possible report threshold. in percentage.
+ * @max_hotlist_bssids: maximum number of entries for hotlist BSSIDs.
+ * @max_hotlist_ssids: maximum number of entries for hotlist SSIDs.
+ * @max_significant_wifi_change_aps: maximum number of entries for significant
+ * change APs.
+ * @max_bssid_history_entries: number of BSSID/RSSI entries that device can
+ * hold.
+ * @max_epno_networks: max number of hashed epno entries.
+ * @max_epno_networks_by_ssid: max number of epno entries for which an
+ * exact match of SSID is required or which are hidded SSIDs.
+ * @max_white_list_ssid: max number of white listed SSIDs.
+ */
+struct wiphy_gscan_caps {
+ u32 max_scan_cache_size;
+ u32 max_scan_buckets;
+ u32 max_ap_cache_per_scan;
+ u32 max_rssi_sample_size;
+ u32 max_scan_reporting_threshold;
+ u32 max_hotlist_bssids;
+ u32 max_hotlist_ssids;
+ u32 max_significant_wifi_change_aps;
+ u32 max_bssid_history_entries;
+ u32 max_epno_hashed_networks;
+ u32 max_epno_exact_networks;
+ u32 max_white_list_ssid;
+};
+
+/**
* struct wiphy - wireless hardware description
* @reg_notifier: the driver's regulatory notification callback,
* note that if your driver uses wiphy_apply_custom_regulatory()
@@ -3524,6 +3558,7 @@ struct wiphy_iftype_ext_capab {
* @bss_select_support: bitmask indicating the BSS selection criteria supported
* by the driver in the .connect() callback. The bit position maps to the
* attribute indices defined in &enum nl80211_bss_select_attr.
+ * @gscan: structure holding the hardware capabilities for gscan.
*
* @cookie_counter: unique generic cookie counter, used to identify objects.
*/
@@ -3654,6 +3689,7 @@ struct wiphy {
u8 max_adj_channel_rssi_comp;
u32 bss_select_support;
+ const struct wiphy_gscan_caps *gscan;
u64 cookie_counter;
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 7e935f6..232a792 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1977,6 +1977,9 @@ enum nl80211_commands {
* @NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED: Indicates whether or not multicast
* packets should be send out as unicast to all stations (flag attribute).
*
+ * @NL80211_ATTR_GSCAN_CAPS: indicating capabilities of GScan functionality
+ * of the device. This is a nested attribute.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2381,6 +2384,8 @@ enum nl80211_attrs {
NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED,
+ NL80211_ATTR_GSCAN_CAPS,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -5188,4 +5193,57 @@ enum nl80211_nan_match_attributes {
NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1
};
+/**
+ * enum nl80211_gscan_caps_attr - GScan capabilities attributes.
+ *
+ * @__NL80211_GSCAN_CAPS_ATTR_INVALID: reserved.
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_CACHE_SIZE: total space allocated for
+ * scan results (in bytes).
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_BUCKETS: maximum number of channel buckets.
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_AP_CACHE_PER_SCAN: maximum number of APs that
+ * can be stored per scan.
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_RSSI_SAMPLE_SIZE: number of RSSI samples used
+ * for averaging RSSI.
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_REPORTING_THRESHOLD: max possible report
+ * threshold. in percentage.
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_HOTLIST_BSSID: maximum number of entries for
+ * hotlist BSSIDs.
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_HOTLIST_SSID: maximum number of entries for
+ * hotlist SSIDs.
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_SIGNIFICANT_WIFI_CHANGE_APS: maximum number of
+ * entries for significant change APs.
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_BSSID_HISTORY: number of BSSID/RSSI entries that
+ * device can hold.
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_EPNO_HASHED_NETWORKS: max number of hashed epno
+ * entries.
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_EPNO_EXACT_NETWORKS: max number of epno entries
+ * for which an exact match of SSID is required or which are hidded SSIDs.
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_WHITE_LIST_SSID: max number of white listed
+ * SSIDs.
+ * @NL80211_GSCAN_CAPS_ATTR_MAX: highest GScan capability attribute.
+ *
+ * @__NL80211_GSCAN_CAPS_ATTR_AFTER_LAST: internal use.
+ *
+ * All attributes are u32 type.
+ */
+enum nl80211_gscan_caps_attr {
+ __NL80211_GSCAN_CAPS_ATTR_INVALID,
+ NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_CACHE_SIZE,
+ NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_BUCKETS,
+ NL80211_GSCAN_CAPS_ATTR_MAX_AP_CACHE_PER_SCAN,
+ NL80211_GSCAN_CAPS_ATTR_MAX_RSSI_SAMPLE_SIZE,
+ NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_REPORTING_THRESHOLD,
+ NL80211_GSCAN_CAPS_ATTR_MAX_HOTLIST_BSSID,
+ NL80211_GSCAN_CAPS_ATTR_MAX_HOTLIST_SSID,
+ NL80211_GSCAN_CAPS_ATTR_MAX_SIGNIFICANT_WIFI_CHANGE_APS,
+ NL80211_GSCAN_CAPS_ATTR_MAX_BSSID_HISTORY,
+ NL80211_GSCAN_CAPS_ATTR_MAX_EPNO_HASHED_NETWORKS,
+ NL80211_GSCAN_CAPS_ATTR_MAX_EPNO_EXACT_NETWORKS,
+ NL80211_GSCAN_CAPS_ATTR_MAX_WHITE_LIST_SSID,
+
+ /* keep last */
+ __NL80211_GSCAN_CAPS_ATTR_AFTER_LAST,
+ NL80211_GSCAN_CAPS_ATTR_MAX = __NL80211_GSCAN_CAPS_ATTR_AFTER_LAST - 1
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ffce566..4606fc9 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1423,9 +1423,10 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
void *hdr;
struct nlattr *nl_bands, *nl_band;
struct nlattr *nl_freqs, *nl_freq;
- struct nlattr *nl_cmds;
+ struct nlattr *nl_cmds, *nl_gscan;
enum nl80211_band band;
struct ieee80211_channel *chan;
+ const struct wiphy_gscan_caps *gscan;
int i;
const struct ieee80211_txrx_stypes *mgmt_stypes =
rdev->wiphy.mgmt_stypes;
@@ -1880,6 +1881,48 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
}
}
+ state->split_start++;
+ break;
+ case 14:
+ if (!rdev->wiphy.gscan) {
+ /* done */
+ state->split_start = 0;
+ break;
+ }
+ gscan = rdev->wiphy.gscan;
+ nl_gscan = nla_nest_start(msg, NL80211_ATTR_GSCAN_CAPS);
+ if (!nl_gscan ||
+ nla_put_u32(msg, NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_CACHE_SIZE,
+ gscan->max_scan_cache_size) ||
+ nla_put_u32(msg, NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_BUCKETS,
+ gscan->max_scan_buckets) ||
+ nla_put_u32(msg, NL80211_GSCAN_CAPS_ATTR_MAX_AP_CACHE_PER_SCAN,
+ gscan->max_ap_cache_per_scan) ||
+ nla_put_u32(msg, NL80211_GSCAN_CAPS_ATTR_MAX_RSSI_SAMPLE_SIZE,
+ gscan->max_rssi_sample_size) ||
+ nla_put_u32(msg,
+ NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_REPORTING_THRESHOLD,
+ gscan->max_scan_reporting_threshold) ||
+ nla_put_u32(msg, NL80211_GSCAN_CAPS_ATTR_MAX_HOTLIST_BSSID,
+ gscan->max_hotlist_bssids) ||
+ nla_put_u32(msg, NL80211_GSCAN_CAPS_ATTR_MAX_HOTLIST_SSID,
+ gscan->max_hotlist_ssids) ||
+ nla_put_u32(msg,
+ NL80211_GSCAN_CAPS_ATTR_MAX_SIGNIFICANT_WIFI_CHANGE_APS,
+ gscan->max_significant_wifi_change_aps) ||
+ nla_put_u32(msg, NL80211_GSCAN_CAPS_ATTR_MAX_BSSID_HISTORY,
+ gscan->max_bssid_history_entries) ||
+ nla_put_u32(msg,
+ NL80211_GSCAN_CAPS_ATTR_MAX_EPNO_HASHED_NETWORKS,
+ gscan->max_epno_hashed_networks) ||
+ nla_put_u32(msg,
+ NL80211_GSCAN_CAPS_ATTR_MAX_EPNO_EXACT_NETWORKS,
+ gscan->max_epno_exact_networks) ||
+ nla_put_u32(msg, NL80211_GSCAN_CAPS_ATTR_MAX_WHITE_LIST_SSID,
+ gscan->max_white_list_ssid))
+ goto nla_put_failure;
+ nla_nest_end(msg, nl_gscan);
+
/* done */
state->split_start = 0;
break;
--
1.9.1
^ permalink raw reply related
* [PATCH 3/5] nl80211: add support for gscan
From: Arend van Spriel @ 2016-11-17 11:39 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1479382792-13131-1-git-send-email-arend.vanspriel@broadcom.com>
This patch adds support for GScan which is a scan offload feature
used in Android.
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
include/net/cfg80211.h | 91 ++++++++++-
include/uapi/linux/nl80211.h | 146 ++++++++++++++++++
net/wireless/core.c | 31 ++++
net/wireless/core.h | 4 +
net/wireless/nl80211.c | 358 ++++++++++++++++++++++++++++++++++++++++++-
net/wireless/rdev-ops.h | 25 +++
net/wireless/scan.c | 28 ++++
net/wireless/trace.h | 9 ++
8 files changed, 685 insertions(+), 7 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index c77bb08..b4b0536 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2464,6 +2464,90 @@ struct cfg80211_nan_func {
};
/**
+ * struct cfg80211_gscan_channel - GScan channel parameters.
+ *
+
+ * @ch: specific channel.
+ * @dwell_time: hint for dwell time in milliseconds.
+ * @passive: indicates passive scan is requested.
+ */
+struct cfg80211_gscan_channel {
+ struct ieee80211_channel *ch;
+ int dwell_time;
+ bool passive;
+};
+
+/**
+ * struct cfg80211_gscan_bucket - GScan bucket parameters.
+ *
+ * @idx: unique bucket index.
+ * @band: bit flags for band(s) to use, see %enum nl80211_bucket_band.
+ * @period: period in which the bucket is scheduled to be scanned. If the
+ * period is too small for driver it should not fail but report results
+ * as fast as it can. For exponential backoff bucket this is the minimum
+ * period.
+ * @report_events: This is a bit field according %enum nl80211_bucket_report_event.
+ * @max_period: used only for the exponential backoff bucket whose scan period will
+ * grow exponentially to a maximum period of max_period.
+ * @exponent: used only for the exponential backoff bucket.
+ * @step_count: used only for the exponential backoff bucket.
+ * @n_channels: number of channels in @channels array.
+ * @channels: channels to scan which may include DFS channels.
+ */
+struct cfg80211_gscan_bucket {
+ int idx;
+ u32 band;
+ int period;
+ u8 report_events;
+ int max_period;
+ int exponent;
+ int step_count;
+ int n_channels;
+ struct cfg80211_gscan_channel *channels;
+};
+
+/**
+ * struct cfg80211_gscan_request - GScan request parameters.
+ *
+ * @flags: scan request flags according %enum nl80211_scan_flags.
+ * @base_period: base timer period in milliseconds.
+ * @max_ap_per_scan: number of APs to store in each scan entry in the BSSID/RSSI
+ * history buffer (keep APS with highest RSSI).
+ * @report_threshold_percent: wake up system when scan buffer is filled to this
+ * percentage.
+ * @report_threshold_num_scans: wake up system when this many scans are stored
+ * in scan buffer.
+ * @mac: MAC address used for randomisation.
+ * @mac_mask: MAC address mask. bits that are 0 in the mask should be
+ * randomised, bits that are 1 should be taken as is from @mac.
+ * @n_buckets: number of entries in @buckets array.
+ * @buckets: array of GScan buckets.
+ *
+ * @dev: net device for which GScan is requested.
+ * @rcu_head: RCU callback used to free the struct.
+ * @owner_nlportid: netlink port which initiated this request.
+ */
+struct cfg80211_gscan_request {
+ u32 flags;
+ int base_period;
+ int max_ap_per_scan;
+ u8 report_threshold_percent;
+ int report_threshold_num_scans;
+ u8 mac[ETH_ALEN];
+ u8 mac_mask[ETH_ALEN];
+
+ int n_buckets;
+
+ /* internal */
+ struct net_device *dev;
+ struct rcu_head rcu_head;
+ u32 owner_nlportid;
+
+ /* keep last */
+ struct cfg80211_gscan_bucket buckets[0];
+};
+
+/**
* struct cfg80211_ops - backend description for wireless configuration
*
* This struct is registered by fullmac card drivers and/or wireless stacks
@@ -2773,8 +2857,9 @@ struct cfg80211_nan_func {
* @nan_change_conf: changes NAN configuration. The changed parameters must
* be specified in @changes (using &enum cfg80211_nan_conf_changes);
* All other parameters must be ignored.
- *
* @set_multicast_to_unicast: configure multicast to unicast conversion for BSS
+ * @start_gscan: start the GSCAN scanning offload.
+ * @stop_gscan: stop the GSCAN scanning offload.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -3055,10 +3140,12 @@ struct cfg80211_ops {
struct wireless_dev *wdev,
struct cfg80211_nan_conf *conf,
u32 changes);
-
int (*set_multicast_to_unicast)(struct wiphy *wiphy,
struct net_device *dev,
const bool enabled);
+ int (*start_gscan)(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_gscan_request *gscan_req);
+ int (*stop_gscan)(struct wiphy *wiphy, struct net_device *dev);
};
/*
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 232a792..8071dae 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -894,6 +894,12 @@
* does not result in a change for the current association. Currently,
* only the %NL80211_ATTR_IE data is used and updated with this command.
*
+ * @NL80211_CMD_START_GSCAN: start GScan.
+ * @NL80211_CMD_STOP_GSCAN: request to stop current GScan.
+ * @NL80211_CMD_GSCAN_STOPPED: indicates that the currently running GScan
+ * has stopped. This event is generated upon @NL80211_CMD_STOP_GSCAN and
+ * the driver may issue this event at any time when a GScan is running.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1093,6 +1099,10 @@ enum nl80211_commands {
NL80211_CMD_UPDATE_CONNECT_PARAMS,
+ NL80211_CMD_START_GSCAN,
+ NL80211_CMD_STOP_GSCAN,
+ NL80211_CMD_GSCAN_STOPPED,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -2385,6 +2395,7 @@ enum nl80211_attrs {
NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED,
NL80211_ATTR_GSCAN_CAPS,
+ NL80211_ATTR_GSCAN_PARAMS,
/* add attributes here, update the policy in nl80211.c */
@@ -4779,12 +4790,15 @@ enum nl80211_connect_failed_reason {
* locally administered 1, multicast 0) is assumed.
* This flag must not be requested when the feature isn't supported, check
* the nl80211 feature flags for the device.
+ * @NL80211_SCAN_FLAGS_IE_DATA: request the device to supply IE data in the
+ * request.
*/
enum nl80211_scan_flags {
NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
NL80211_SCAN_FLAG_FLUSH = 1<<1,
NL80211_SCAN_FLAG_AP = 1<<2,
NL80211_SCAN_FLAG_RANDOM_ADDR = 1<<3,
+ NL80211_SCAN_FLAG_IE_DATA = 1<<4,
};
/**
@@ -5246,4 +5260,136 @@ enum nl80211_gscan_caps_attr {
NL80211_GSCAN_CAPS_ATTR_MAX = __NL80211_GSCAN_CAPS_ATTR_AFTER_LAST - 1
};
+/**
+ * enum nl80211_gscan_attr - common GScan parameters.
+ *
+ * @__NL80211_GSCAN_ATTR_INVALID: reserved.
+ * @NL80211_GSCAN_ATTR_BASE_PERIOD: base timer period in milliseconds.
+ * @NL80211_GSCAN_ATTR_MAX_AP_PER_SCAN: number of APs that are kept per
+ * scan. The kept APs are the ones with strongest RSSI level.
+ * @NL80211_GSCAN_ATTR_REPORT_PERC: threshold specifying percentage of
+ * scan cache filled that should trigger event for scan results.
+ * @NL80211_GSCAN_ATTR_REPORT_SCANS: threshold specifying number of scans
+ * after which an event is expected for scan results.
+ * @NL80211_GSCAN_ATTR_BUCKETS: nested attribute specifying
+ * per-bucket parameters for GScan. See %enum nl80211_gscan_bucket_attr
+ * for description.
+ * @NL80211_GSCAN_ATTR_MAX: highest GScan attribute.
+ * @__NL80211_GSCAN_ATTR_AFTER_LAST: internal use.
+ */
+enum nl80211_gscan_attr {
+ __NL80211_GSCAN_ATTR_INVALID,
+ NL80211_GSCAN_ATTR_BASE_PERIOD,
+ NL80211_GSCAN_ATTR_MAX_AP_PER_SCAN,
+ NL80211_GSCAN_ATTR_REPORT_PERC,
+ NL80211_GSCAN_ATTR_REPORT_SCANS,
+ NL80211_GSCAN_ATTR_BUCKETS,
+
+ /* keep last */
+ __NL80211_GSCAN_ATTR_AFTER_LAST,
+ NL80211_GSCAN_ATTR_MAX = __NL80211_GSCAN_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_gscan_bucket_attr - per-bucket GScan parameters.
+ *
+ * @__NL80211_GSCAN_BUCKET_ATTR_INVALID,
+ * @NL80211_GSCAN_BUCKET_ATTR_ID: unique bucket id.
+ * @NL80211_GSCAN_BUCKET_ATTR_BAND: specifies the band to be scanned
+ * according %enum nl80211_bucket_band. If specified
+ * @NL80211_GSCAN_BUCKET_ATTR_CHANNELS is ignored.
+ * @NL80211_GSCAN_BUCKET_ATTR_PERIOD: specifies the period between
+ * consecutive scans of this bucket. For backoff bucket this
+ * is period(0).
+ * @NL80211_GSCAN_BUCKET_ATTR_REPORT: specifies reporting flags according
+ * %enum nl80211_bucket_report_event.
+ * @NL80211_GSCAN_BUCKET_ATTR_MAX_PERIOD: maximum period between
+ * consecutive scans. If specified this is a backoff bucket in
+ * which the period increases according formula:
+ * period(N) = period(0) * (base ^ (N/step_count))
+ * @NL80211_GSCAN_BUCKET_ATTR_EXPONENT: exponential base value as used
+ * in given formula. This attribute is required when
+ * @NL80211_GSCAN_BUCKET_ATTR_MAX_PERIOD is specified.
+ * @NL80211_GSCAN_BUCKET_ATTR_STEPS: step count as used in given formula.
+ * This attribute is required when @NL80211_GSCAN_BUCKET_ATTR_MAX_PERIOD
+ * is specified.
+ * @NL80211_GSCAN_BUCKET_ATTR_CHANNELS: nested attribute specifying the
+ * channels that are to be scanned for this bucket.
+ * @NL80211_GSCAN_BUCKET_ATTR_MAX: highest GScan bucket attribute.
+ * @__NL80211_GSCAN_BUCKET_ATTR_AFTER_LAST: internal use.
+ */
+enum nl80211_gscan_bucket_attr {
+ __NL80211_GSCAN_BUCKET_ATTR_INVALID,
+ NL80211_GSCAN_BUCKET_ATTR_ID,
+ NL80211_GSCAN_BUCKET_ATTR_BAND,
+ NL80211_GSCAN_BUCKET_ATTR_PERIOD,
+ NL80211_GSCAN_BUCKET_ATTR_REPORT,
+ NL80211_GSCAN_BUCKET_ATTR_MAX_PERIOD,
+ NL80211_GSCAN_BUCKET_ATTR_EXPONENT,
+ NL80211_GSCAN_BUCKET_ATTR_STEPS,
+ NL80211_GSCAN_BUCKET_ATTR_CHANNELS,
+
+ /* keep last */
+ __NL80211_GSCAN_BUCKET_ATTR_AFTER_LAST,
+ NL80211_GSCAN_BUCKET_ATTR_MAX = __NL80211_GSCAN_BUCKET_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_gscan_chan_attr - GScan bucket channel parameters.
+ *
+ * @__NL80211_GSCAN_CHAN_ATTR_INVALID: reserved.
+ * @NL80211_GSCAN_CHAN_ATTR_FREQ: frequency of channel.
+ * @NL80211_GSCAN_CHAN_ATTR_DWELL_TIME: dwell time to be used for scanning
+ * this channel.
+ * @NL80211_GSCAN_CHAN_ATTR_NO_IR: scanning should be done passive.
+ * @NL80211_GSCAN_CHAN_ATTR_MAX: highest GScan channel attribute.
+ * @__NL80211_GSCAN_CHAN_ATTR_AFTER_LAST: internal use.
+ */
+enum nl80211_gscan_chan_attr {
+ __NL80211_GSCAN_CHAN_ATTR_INVALID,
+ NL80211_GSCAN_CHAN_ATTR_FREQ,
+ NL80211_GSCAN_CHAN_ATTR_DWELL_TIME,
+ NL80211_GSCAN_CHAN_ATTR_NO_IR,
+
+ /* keep last */
+ __NL80211_GSCAN_CHAN_ATTR_AFTER_LAST,
+ NL80211_GSCAN_CHAN_ATTR_MAX = __NL80211_GSCAN_CHAN_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_bucket_band - GScan bucket band selection.
+ *
+ * @NL80211_BUCKET_BAND_2GHZ: consider all device supported channels
+ * in 2G band.
+ * @NL80211_BUCKET_BAND_5GHZ: consider all device supported channels
+ * in 5G band, ie. both DFS and non-DFS when @NL80211_BUCKET_BAND_NODFS
+ * and @NL80211_BUCKET_BAND_DFS_ONLY are not set.
+ * @NL80211_BUCKET_BAND_NODFS: only consider non-DFS channels. Only
+ * applicable when 5G band is selected, otherwise ignored.
+ * @NL80211_BUCKET_BAND_DFS_ONLY: only consider DFS channels. Only
+ * applicable when 5G band is selected, otherwise ignored.
+ *
+ * Setting both @NL80211_BUCKET_BAND_NODFS and @NL80211_BUCKET_BAND_DFS_ONLY
+ * is considerd invalid.
+ */
+enum nl80211_bucket_band {
+ NL80211_BUCKET_BAND_2GHZ = (1 << 0),
+ NL80211_BUCKET_BAND_5GHZ = (1 << 1),
+ NL80211_BUCKET_BAND_NODFS = (1 << 2),
+ NL80211_BUCKET_BAND_DFS_ONLY = (1 << 3),
+};
+
+/**
+ * enum nl80211_bucket_report_event - GScan bucket report flags.
+ *
+ * @NL80211_BUCKET_REPORT_EACH_SCAN: trigger event after each scan.
+ * @NL80211_BUCKET_REPORT_FULL_RESULTS: report full scan results.
+ * @NL80211_BUCKET_REPORT_NO_BATCH: no batching required.
+ */
+enum nl80211_bucket_report_event {
+ NL80211_BUCKET_REPORT_EACH_SCAN = (1 << 0),
+ NL80211_BUCKET_REPORT_FULL_RESULTS = (1 << 1),
+ NL80211_BUCKET_REPORT_NO_BATCH = (1 << 2),
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 158c59e..760a2fb 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -357,6 +357,20 @@ static void cfg80211_sched_scan_stop_wk(struct work_struct *work)
rtnl_unlock();
}
+static void cfg80211_gscan_stop_wk(struct work_struct *work)
+{
+ struct cfg80211_registered_device *rdev;
+
+ rdev = container_of(work, struct cfg80211_registered_device,
+ gscan_stop_wk);
+
+ rtnl_lock();
+
+ __cfg80211_stop_gscan(rdev, false);
+
+ rtnl_unlock();
+}
+
/* exported functions */
struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
@@ -383,6 +397,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
WARN_ON(ops->remain_on_channel && !ops->cancel_remain_on_channel);
WARN_ON(ops->tdls_channel_switch && !ops->tdls_cancel_channel_switch);
WARN_ON(ops->add_tx_ts && !ops->del_tx_ts);
+ WARN_ON(ops->start_gscan && !ops->stop_gscan);
alloc_size = sizeof(*rdev) + sizeof_priv;
@@ -456,6 +471,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
spin_lock_init(&rdev->destroy_list_lock);
INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk);
INIT_WORK(&rdev->sched_scan_stop_wk, cfg80211_sched_scan_stop_wk);
+ INIT_WORK(&rdev->gscan_stop_wk, cfg80211_gscan_stop_wk);
#ifdef CONFIG_CFG80211_DEFAULT_PS
rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -690,6 +706,12 @@ int wiphy_register(struct wiphy *wiphy)
(wiphy->bss_select_support & ~(BIT(__NL80211_BSS_SELECT_ATTR_AFTER_LAST) - 2))))
return -EINVAL;
+ /* buckets must have unique index and in nl80211 parsing
+ * a u32 is used to verify that hence this limit.
+ */
+ if (WARN_ON(wiphy->gscan && wiphy->gscan->max_scan_buckets > 32))
+ return -EINVAL;
+
if (wiphy->addresses)
memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN);
@@ -1001,6 +1023,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
{
struct net_device *dev = wdev->netdev;
struct cfg80211_sched_scan_request *sched_scan_req;
+ struct cfg80211_gscan_request *gscan_req;
ASSERT_RTNL();
ASSERT_WDEV_LOCK(wdev);
@@ -1014,6 +1037,9 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
if (sched_scan_req && dev == sched_scan_req->dev)
__cfg80211_stop_sched_scan(rdev, false);
+ gscan_req = rtnl_dereference(rdev->gscan_req);
+ if (gscan_req && dev == gscan_req->dev)
+ __cfg80211_stop_gscan(rdev, false);
#ifdef CONFIG_CFG80211_WEXT
kfree(wdev->wext.ie);
@@ -1089,6 +1115,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev;
struct cfg80211_sched_scan_request *sched_scan_req;
+ struct cfg80211_gscan_request *gscan_req;
if (!wdev)
return NOTIFY_DONE;
@@ -1160,6 +1187,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
sched_scan_req->dev == wdev->netdev)) {
__cfg80211_stop_sched_scan(rdev, false);
}
+ gscan_req = rtnl_dereference(rdev->gscan_req);
+ if (WARN_ON(gscan_req && gscan_req->dev == wdev->netdev)) {
+ __cfg80211_stop_gscan(rdev, false);
+ }
rdev->opencount--;
wake_up(&rdev->dev_wait);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index fb2fcd5..b0f2519 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -74,6 +74,7 @@ struct cfg80211_registered_device {
struct cfg80211_scan_request *scan_req; /* protected by RTNL */
struct sk_buff *scan_msg;
struct cfg80211_sched_scan_request __rcu *sched_scan_req;
+ struct cfg80211_gscan_request __rcu *gscan_req;
unsigned long suspend_at;
struct work_struct scan_done_wk;
struct work_struct sched_scan_results_wk;
@@ -95,6 +96,7 @@ struct cfg80211_registered_device {
struct work_struct destroy_work;
struct work_struct sched_scan_stop_wk;
+ struct work_struct gscan_stop_wk;
/* must be last because of the way we do wiphy_priv(),
* and it should at least be aligned to NETDEV_ALIGN */
@@ -421,6 +423,8 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
void __cfg80211_sched_scan_results(struct work_struct *wk);
int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
bool driver_initiated);
+int __cfg80211_stop_gscan(struct cfg80211_registered_device *rdev,
+ bool driver_initiated);
void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
struct net_device *dev, enum nl80211_iftype ntype,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4606fc9..8fc3cbe 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -404,6 +404,7 @@ enum nl80211_multicast_groups {
.len = FILS_MAX_KEK_LEN },
[NL80211_ATTR_FILS_NONCES] = { .len = 2 * FILS_NONCE_LEN },
[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
+ [NL80211_ATTR_GSCAN_PARAMS] = { .type = NLA_NESTED },
};
/* policy for the key attributes */
@@ -11860,6 +11861,325 @@ static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
return rdev_set_multicast_to_unicast(rdev, dev, enabled);
}
+static const
+struct nla_policy nl80211_gscan_policy[NL80211_GSCAN_ATTR_MAX + 1] = {
+ [NL80211_GSCAN_ATTR_BASE_PERIOD] = { .type = NLA_U32 },
+ [NL80211_GSCAN_ATTR_MAX_AP_PER_SCAN] = { .type = NLA_U32 },
+ [NL80211_GSCAN_ATTR_REPORT_PERC] = { .type = NLA_U8 },
+ [NL80211_GSCAN_ATTR_REPORT_SCANS] = { .type = NLA_U32 },
+ [NL80211_GSCAN_ATTR_BUCKETS] = { .type = NLA_NESTED },
+};
+
+static const struct nla_policy
+nl80211_gscan_bucket_policy[NL80211_GSCAN_BUCKET_ATTR_MAX + 1] = {
+ [NL80211_GSCAN_BUCKET_ATTR_ID] = { .type = NLA_U32 },
+ [NL80211_GSCAN_BUCKET_ATTR_BAND] = { .type = NLA_U32 },
+ [NL80211_GSCAN_BUCKET_ATTR_PERIOD] = { .type = NLA_U32 },
+ [NL80211_GSCAN_BUCKET_ATTR_REPORT] = { .type = NLA_U32 },
+ [NL80211_GSCAN_BUCKET_ATTR_MAX_PERIOD] = { .type = NLA_U32 },
+ [NL80211_GSCAN_BUCKET_ATTR_EXPONENT] = { .type = NLA_U32 },
+ [NL80211_GSCAN_BUCKET_ATTR_STEPS] = { .type = NLA_U32 },
+ [NL80211_GSCAN_BUCKET_ATTR_CHANNELS] = { .type = NLA_NESTED },
+};
+
+static const struct nla_policy
+nl80211_gscan_channel_policy[NL80211_GSCAN_CHAN_ATTR_MAX + 1] = {
+ [NL80211_GSCAN_CHAN_ATTR_FREQ] = { .type = NLA_U32 },
+ [NL80211_GSCAN_CHAN_ATTR_DWELL_TIME] = { .type = NLA_U32 },
+ [NL80211_GSCAN_CHAN_ATTR_NO_IR] = { .type = NLA_FLAG },
+};
+
+static int nl80211_parse_gscan_channel(struct cfg80211_registered_device *rdev,
+ struct nlattr *nattr,
+ struct cfg80211_gscan_channel *chan)
+{
+ struct nlattr *tb[NL80211_GSCAN_CHAN_ATTR_MAX + 1];
+ struct ieee80211_channel *ch;
+ int err;
+
+ err = nla_parse(tb, NL80211_GSCAN_CHAN_ATTR_MAX, nla_data(nattr),
+ nla_len(nattr), nl80211_gscan_channel_policy);
+ if (err)
+ return err;
+
+ if (!tb[NL80211_GSCAN_CHAN_ATTR_FREQ])
+ return -EINVAL;
+
+ ch = ieee80211_get_channel(&rdev->wiphy,
+ nla_get_u32(tb[NL80211_GSCAN_CHAN_ATTR_FREQ]));
+ if (!ch || (ch->flags & IEEE80211_CHAN_DISABLED))
+ return -EINVAL;
+
+ chan->ch = ch;
+
+ if (tb[NL80211_GSCAN_CHAN_ATTR_DWELL_TIME])
+ chan->dwell_time = nla_get_u32(tb[NL80211_GSCAN_CHAN_ATTR_DWELL_TIME]);
+ if (tb[NL80211_GSCAN_CHAN_ATTR_NO_IR])
+ chan->passive = true;
+ return 0;
+}
+
+static int nl80211_parse_gscan_bucket(struct cfg80211_registered_device *rdev,
+ struct nlattr *nattr,
+ struct cfg80211_gscan_bucket *bucket,
+ struct cfg80211_gscan_channel *channels)
+{
+ struct nlattr *tb[NL80211_GSCAN_BUCKET_ATTR_MAX + 1];
+ struct nlattr *chan;
+ struct cfg80211_gscan_channel *ch;
+ int err, rem;
+ int num_chans = 0;
+ u32 band_select = 0;
+ u32 dfs_invalid_mask;
+
+ err = nla_parse(tb, NL80211_GSCAN_BUCKET_ATTR_MAX, nla_data(nattr),
+ nla_len(nattr), nl80211_gscan_bucket_policy);
+ if (err)
+ return err;
+
+ if (!tb[NL80211_GSCAN_BUCKET_ATTR_ID] ||
+ !tb[NL80211_GSCAN_BUCKET_ATTR_PERIOD])
+ return -EINVAL;
+
+ bucket->idx = nla_get_u32(tb[NL80211_GSCAN_BUCKET_ATTR_ID]);
+ if (tb[NL80211_GSCAN_BUCKET_ATTR_BAND]) {
+ band_select = nla_get_u32(tb[NL80211_GSCAN_BUCKET_ATTR_BAND]);
+
+ /* only makes sense if a band is selected */
+ if (!(band_select & (NL80211_BUCKET_BAND_2GHZ | NL80211_BUCKET_BAND_5GHZ)))
+ return -EINVAL;
+ }
+
+ dfs_invalid_mask = NL80211_BUCKET_BAND_5GHZ | NL80211_BUCKET_BAND_NODFS |
+ NL80211_BUCKET_BAND_DFS_ONLY;
+ if ((band_select & dfs_invalid_mask) == dfs_invalid_mask)
+ return -EINVAL;
+
+ bucket->band = band_select;
+ bucket->period = nla_get_u32(tb[NL80211_GSCAN_BUCKET_ATTR_PERIOD]);
+
+ if (tb[NL80211_GSCAN_BUCKET_ATTR_MAX_PERIOD])
+ bucket->max_period = nla_get_u32(tb[NL80211_GSCAN_BUCKET_ATTR_MAX_PERIOD]);
+
+ if (bucket->max_period) {
+ if (bucket->max_period < bucket->period)
+ return -EINVAL;
+ /* additional attributes required for backoff bucket */
+ if (bucket->max_period > bucket->period) {
+ if (!tb[NL80211_GSCAN_BUCKET_ATTR_EXPONENT] ||
+ !tb[NL80211_GSCAN_BUCKET_ATTR_STEPS])
+ return -EINVAL;
+
+ bucket->exponent = nla_get_u32(tb[NL80211_GSCAN_BUCKET_ATTR_EXPONENT]);
+ bucket->step_count = nla_get_u32(tb[NL80211_GSCAN_BUCKET_ATTR_STEPS]);
+ }
+ }
+
+ /* ignore channels if band is specified */
+ if (band_select)
+ return 0;
+
+ nla_for_each_nested(chan, tb[NL80211_GSCAN_BUCKET_ATTR_CHANNELS], rem) {
+ num_chans++;
+ }
+ if (num_chans > 16)
+ return -EINVAL;
+
+ bucket->n_channels = num_chans;
+ if (!num_chans)
+ return 0;
+
+ bucket->channels = channels;
+ ch = &bucket->channels[0];
+ nla_for_each_nested(chan, tb[NL80211_GSCAN_BUCKET_ATTR_CHANNELS], rem) {
+ err = nl80211_parse_gscan_channel(rdev, chan, ch);
+ if (err) {
+ return err;
+ }
+ ch++;
+ }
+
+ return 0;
+}
+
+static struct cfg80211_gscan_request *
+nl80211_alloc_gscan_request(struct cfg80211_registered_device *rdev,
+ struct nlattr *buckets_attr)
+{
+ struct cfg80211_gscan_request *req;
+ struct cfg80211_gscan_bucket *b;
+ struct cfg80211_gscan_channel *ch;
+ int n_buckets, n_channels;
+ struct nlattr *attr, *bucket, *channel;
+ int rem, rem_b, rem_c;
+ size_t reqsize;
+
+ if (!buckets_attr)
+ return ERR_PTR(-EINVAL);
+
+ n_buckets = 0;
+ n_channels = 0;
+ nla_for_each_nested(bucket, buckets_attr, rem) {
+ n_buckets++;
+ if (n_buckets > rdev->wiphy.gscan->max_scan_buckets)
+ return ERR_PTR(-EINVAL);
+
+ nla_for_each_nested(attr, bucket, rem_b) {
+ if (nla_type(attr) == NL80211_GSCAN_BUCKET_ATTR_CHANNELS) {
+ nla_for_each_nested(channel, attr, rem_c)
+ n_channels++;
+ }
+ }
+ }
+
+ reqsize = sizeof(*req) +
+ sizeof(*b) * n_buckets +
+ sizeof(*ch) * n_channels;
+
+ pr_err("%s: buckets(%zu) %d channels(%zu) %d reqsize %zu (%zx)\n",
+ __func__, sizeof(*b), n_buckets, sizeof(*ch), n_channels,
+ reqsize, reqsize);
+
+ req = kzalloc(reqsize, GFP_KERNEL);
+ if (!req)
+ return ERR_PTR(-ENOMEM);
+
+ req->n_buckets = n_buckets;
+ return req;
+}
+
+static int nl80211_parse_gscan_params(struct cfg80211_registered_device *rdev,
+ struct nlattr *attrs[],
+ struct cfg80211_gscan_request **request)
+{
+ struct cfg80211_gscan_request *req;
+ struct nlattr *tb[NL80211_GSCAN_ATTR_MAX + 1];
+ struct nlattr *bucket;
+ struct cfg80211_gscan_bucket *b;
+ struct cfg80211_gscan_channel *ch;
+ int err, rem, i;
+ u32 bucket_map;
+
+ if (!attrs[NL80211_ATTR_GSCAN_PARAMS])
+ return -EINVAL;
+
+ err = nla_parse(tb, NL80211_GSCAN_ATTR_MAX,
+ nla_data(attrs[NL80211_ATTR_GSCAN_PARAMS]),
+ nla_len(attrs[NL80211_ATTR_GSCAN_PARAMS]),
+ nl80211_gscan_policy);
+ if (err)
+ return err;
+
+ req = nl80211_alloc_gscan_request(rdev, tb[NL80211_GSCAN_ATTR_BUCKETS]);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ if (!tb[NL80211_GSCAN_ATTR_BASE_PERIOD])
+ return -EINVAL;
+
+ req->base_period = nla_get_u32(tb[NL80211_GSCAN_ATTR_BASE_PERIOD]);
+
+ if (tb[NL80211_GSCAN_ATTR_MAX_AP_PER_SCAN])
+ req->max_ap_per_scan = nla_get_u32(tb[NL80211_GSCAN_ATTR_MAX_AP_PER_SCAN]);
+ if (tb[NL80211_GSCAN_ATTR_REPORT_PERC])
+ req->report_threshold_percent = nla_get_u8(tb[NL80211_GSCAN_ATTR_REPORT_PERC]);
+ if (tb[NL80211_GSCAN_ATTR_REPORT_SCANS])
+ req->report_threshold_num_scans = nla_get_u32(tb[NL80211_GSCAN_ATTR_REPORT_SCANS]);
+ if (attrs[NL80211_ATTR_MAC])
+ memcpy(req->mac, nla_data(attrs[NL80211_ATTR_MAC]), ETH_ALEN);
+ if (attrs[NL80211_ATTR_MAC_MASK])
+ memcpy(req->mac_mask, nla_data(attrs[NL80211_ATTR_MAC_MASK]),
+ ETH_ALEN);
+ if (attrs[NL80211_ATTR_SCAN_FLAGS])
+ req->flags = nla_get_u32(attrs[NL80211_ATTR_SCAN_FLAGS]);
+
+ pr_err("%s: req %p flags %x\n", __func__, req, req->flags);
+ b = &req->buckets[0];
+ ch = (struct cfg80211_gscan_channel *)(&req->buckets[req->n_buckets]);
+ nla_for_each_nested(bucket, tb[NL80211_GSCAN_ATTR_BUCKETS], rem) {
+ err = nl80211_parse_gscan_bucket(rdev, bucket, b, ch);
+ if (err)
+ goto free_req;
+ pr_err("%s: bucket[%d]: b=%p, b->channels=%p, b->n_channels=%d\n",
+ __func__, b->idx, b, b->channels, b->n_channels);
+ ch += b->n_channels;
+ b++;
+ }
+ bucket_map = 0;
+ for (i = 0; i < req->n_buckets; i++) {
+ if (BIT(req->buckets[i].idx) & bucket_map) {
+ err = -EINVAL;
+ goto free_req;
+ }
+ bucket_map |= BIT(req->buckets[i].idx);
+
+ if (req->buckets[i].period % req->base_period) {
+ err = -EINVAL;
+ goto free_req;
+ }
+ if (req->buckets[i].max_period &&
+ (req->buckets[i].max_period % req->base_period)) {
+ err = -EINVAL;
+ goto free_req;
+ }
+ }
+ *request = req;
+ return 0;
+
+free_req:
+ kfree(req);
+ return err;
+}
+
+static int nl80211_start_gscan(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_gscan_request *request;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ if (!rdev->wiphy.gscan ||
+ !rdev->ops->start_gscan)
+ return -EOPNOTSUPP;
+
+ if (rdev->gscan_req)
+ return -EINPROGRESS;
+
+ err = nl80211_parse_gscan_params(rdev, info->attrs, &request);
+ if (err)
+ return err;
+
+ wdev_lock(wdev);
+ err = rdev_start_gscan(rdev, dev, request);
+ wdev_unlock(wdev);
+ if (err) {
+ kfree(request);
+ return err;
+ }
+
+ request->dev = dev;
+ if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
+ request->owner_nlportid = info->snd_portid;
+
+ rcu_assign_pointer(rdev->gscan_req, request);
+
+ nl80211_send_scan_event(rdev, dev,
+ NL80211_CMD_START_GSCAN);
+ return 0;
+}
+
+static int nl80211_stop_gscan(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+
+ if (!rdev->wiphy.gscan ||
+ !rdev->ops->stop_gscan)
+ return -EOPNOTSUPP;
+
+ return __cfg80211_stop_gscan(rdev, false);
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -12735,6 +13055,22 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_START_GSCAN,
+ .doit = nl80211_start_gscan,
+ .policy = nl80211_policy,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL80211_CMD_STOP_GSCAN,
+ .doit = nl80211_stop_gscan,
+ .policy = nl80211_policy,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_family nl80211_fam __ro_after_init = {
@@ -14540,12 +14876,18 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
bool schedule_destroy_work = false;
bool schedule_scan_stop = false;
+ bool schedule_gscan_stop = false;
struct cfg80211_sched_scan_request *sched_scan_req =
rcu_dereference(rdev->sched_scan_req);
+ struct cfg80211_gscan_request *gscan_req =
+ rcu_dereference(rdev->gscan_req);
if (sched_scan_req && notify->portid &&
sched_scan_req->owner_nlportid == notify->portid)
schedule_scan_stop = true;
+ if (gscan_req && notify->portid &&
+ gscan_req->owner_nlportid == notify->portid)
+ schedule_gscan_stop = true;
list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
cfg80211_mlme_unregister_socket(wdev, notify->portid);
@@ -14576,12 +14918,18 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
spin_unlock(&rdev->destroy_list_lock);
schedule_work(&rdev->destroy_work);
}
- } else if (schedule_scan_stop) {
- sched_scan_req->owner_nlportid = 0;
+ } else {
+ if (schedule_scan_stop) {
+ sched_scan_req->owner_nlportid = 0;
- if (rdev->ops->sched_scan_stop &&
- rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
- schedule_work(&rdev->sched_scan_stop_wk);
+ if (rdev->ops->sched_scan_stop &&
+ rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
+ schedule_work(&rdev->sched_scan_stop_wk);
+ }
+ if (schedule_gscan_stop) {
+ gscan_req->owner_nlportid = 0;
+ schedule_work(&rdev->gscan_stop_wk);
+ }
}
}
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 2f42507..196e6a7 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1153,4 +1153,29 @@ static inline int rdev_set_qos_map(struct cfg80211_registered_device *rdev,
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
+
+static inline int
+rdev_start_gscan(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_gscan_request *request)
+{
+ int ret;
+
+ trace_rdev_start_gscan(&rdev->wiphy, dev);
+ ret = rdev->ops->start_gscan(&rdev->wiphy, dev, request);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
+static inline int
+rdev_stop_gscan(struct cfg80211_registered_device *rdev,
+ struct net_device *dev)
+{
+ int ret;
+
+ trace_rdev_stop_gscan(&rdev->wiphy, dev);
+ ret = rdev->ops->stop_gscan(&rdev->wiphy, dev);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
#endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index afda1f9..8bd8290 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -335,6 +335,34 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
return 0;
}
+int __cfg80211_stop_gscan(struct cfg80211_registered_device *rdev,
+ bool driver_initiated)
+{
+ struct cfg80211_gscan_request *gscan_req;
+ struct net_device *dev;
+
+ ASSERT_RTNL();
+
+ if (!rdev->gscan_req)
+ return -ENOENT;
+
+ gscan_req = rtnl_dereference(rdev->gscan_req);
+ dev = gscan_req->dev;
+
+ if (!driver_initiated) {
+ int err = rdev_stop_gscan(rdev, dev);
+ if (err)
+ return err;
+ }
+
+ nl80211_send_scan_event(rdev, dev, NL80211_CMD_GSCAN_STOPPED);
+
+ RCU_INIT_POINTER(rdev->gscan_req, NULL);
+ kfree_rcu(gscan_req, rcu_head);
+
+ return 0;
+}
+
void cfg80211_bss_age(struct cfg80211_registered_device *rdev,
unsigned long age_secs)
{
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index ea1b47e..1d0fde9 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -3067,6 +3067,15 @@
WIPHY_PR_ARG, NETDEV_PR_ARG,
BOOL_TO_STR(__entry->enabled))
);
+
+DEFINE_EVENT(wiphy_netdev_evt, rdev_start_gscan,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+ TP_ARGS(wiphy, netdev)
+);
+DEFINE_EVENT(wiphy_netdev_evt, rdev_stop_gscan,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+ TP_ARGS(wiphy, netdev)
+);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
--
1.9.1
^ permalink raw reply related
* [RFC 0/5] nl80211: add support for g-scan
From: Arend van Spriel @ 2016-11-17 11:39 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel
Android employs a Wifi-HAL layer in its wireless frame. It basically abstracts
dealing with netlink messages from the framework. For some features it employs
nl80211 vendor commands. The goal I set myself is to be able to have a generic
nl80211 Wifi-HAL implementation. One of the features currently requiring the
vendor commands is g-scan. We can only guess what the 'g' stands for ;-) This
series converts the vendor command api into common nl80211 api.
Before making an attempt to explain more about the g-scan functionality first
this. While I am still testing the driver implementation resulting in numerous
questions Dmitry send the email below to bring a related discussion to the
table..eh.. the linux-wireless list. This is probably a good thing as anyone
can dive in and share their thoughts.
On 16-11-2016 23:47, dimitrysh@google.com wrote:
> From 68a9d37a4c7e9dc7a90a6e922cdea52737a98d66 Mon Sep 17 00:00:00 2001
> From: Dmitry Shmidt <dimitrysh@google.com>
> Date: Wed, 16 Nov 2016 14:27:26 -0800
> Subject: [PATCH] RFC: Universal scan proposal
>
> Currently we have sched scan with possibility of various
> intervals. We would like to extend it to support also
> different types of scan.
Extending would be an option, but replacing sched_scan by uscan does not
seem like a good idea although you are only redefining the driver api, but
it seems elaborate to map all user-space scans to the new uscan callback.
> In case of powerful wlan CPU, all this functionality
> can be offloaded.
> In general case FW processes additional scan requests
> and puts them into queue based on start time and interval.
> Once current request is fulfilled, FW adds it (if interval != 0)
> again to the queue with proper interval. If requests are
> overlapping, new request can be combined with either one before,
> or one after, assuming that requests are not mutually exclusive.
> Combining requests is done by combining scan channels, ssids,
> bssids and types of scan result. Once combined request was fulfilled
> it will be reinserted as two (or three) different requests based on
> their type and interval.
> Each request has attribute:
> Type: connectivity / location
> Report: none / batch / immediate
These probably need more explanation. The 'Type' attribute gives hint about
the high-level use-case, ie. (android) connectivity or location service. This
obviously should have a different behaviour in the driver/device so we need to
describe that behaviour.
> Request may have priority and can be inserted into
> the head of the queue.
> Types of scans:
> - Normal scan
> - Scheduled scan
> - Hotlist (BSSID scan)
> - Roaming
> - AutoJoin
Are these last two really scans? How should AutoJoin work dealing with the
connection state of wpa_supplicant and driver/device if establishing the
connection is entirely offloaded including eapol handshakes and key derivation.
Now getting back to this series, it adds basic support of g-scan (or GScan, or
gscan, or something completely different; suggestions are welcome). A basic
g-scan request consists of some common attributes and so-called buckets. Each
bucket represents a re-occurring scan request with a given interval and a set
of channels. The common attributes specify how much scans (m) should be stored
and how many BSS-es (n) should be kept per scan before an event is sent. The
other option is to specify a percentage at which an event is sent, where 100%
equals (m * n). It also specifies the base period, but we may drop that as it
is the gcd() of the individual buckets. A special case of bucket is the
exponential backoff bucket, which has a increasing interval.
Whether this type of scan offload is a good addition depends on the high-level
use-case(s). It would help this discussion greatly to know those use-case(s).
A current hurdle for me is that the device stores m scans so a BSS could end up
in the result of either of them. However, cfg80211 stores BSS-es uniquely with
latest scan information. Does user-space need results per scan or is flat BSS
storage fine.
Anyway, here is some more fuel to the discussion.
Regards,
Arend
Arend van Spriel (5):
nl80211: allow reporting RTT information in scan results
nl80211: add reporting of gscan capabilities
nl80211: add support for gscan
nl80211: rename some notification functions
nl80211: add driver api for gscan notifications
include/net/cfg80211.h | 166 +++++++++++++++-
include/uapi/linux/nl80211.h | 212 +++++++++++++++++++++
net/wireless/core.c | 33 ++++
net/wireless/core.h | 6 +
net/wireless/nl80211.c | 440 +++++++++++++++++++++++++++++++++++++++++--
net/wireless/nl80211.h | 4 +-
net/wireless/rdev-ops.h | 25 +++
net/wireless/scan.c | 95 +++++++++-
net/wireless/trace.h | 19 ++
9 files changed, 984 insertions(+), 16 deletions(-)
--
1.9.1
^ permalink raw reply
* [PATCH 4/5] nl80211: rename some notification functions
From: Arend van Spriel @ 2016-11-17 11:39 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1479382792-13131-1-git-send-email-arend.vanspriel@broadcom.com>
The functions nl80211_send_sched_scan() and nl80211_send_sched_scan_msg()
take command as parameter, which strictly speaking makes them general
purpose and not directly related to scheduled scan functionality. The
message are sent to "scan" multicast group so renaming them to
nl80211_send_scan_event{,_msg}().
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
net/wireless/nl80211.c | 10 +++++-----
net/wireless/nl80211.h | 2 +-
net/wireless/scan.c | 4 ++--
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 8fc3cbe..5b22310 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -7237,7 +7237,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);
- nl80211_send_sched_scan(rdev, dev,
+ nl80211_send_scan_event(rdev, dev,
NL80211_CMD_START_SCHED_SCAN);
return 0;
@@ -13214,7 +13214,7 @@ static int nl80211_send_scan_msg(struct sk_buff *msg,
}
static int
-nl80211_send_sched_scan_msg(struct sk_buff *msg,
+nl80211_send_scan_event_msg(struct sk_buff *msg,
struct cfg80211_registered_device *rdev,
struct net_device *netdev,
u32 portid, u32 seq, int flags, u32 cmd)
@@ -13294,7 +13294,7 @@ void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
if (!msg)
return;
- if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0,
+ if (nl80211_send_scan_event_msg(msg, rdev, netdev, 0, 0, 0,
NL80211_CMD_SCHED_SCAN_RESULTS) < 0) {
nlmsg_free(msg);
return;
@@ -13304,7 +13304,7 @@ void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
NL80211_MCGRP_SCAN, GFP_KERNEL);
}
-void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
+void nl80211_send_scan_event(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u32 cmd)
{
struct sk_buff *msg;
@@ -13313,7 +13313,7 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
if (!msg)
return;
- if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
+ if (nl80211_send_scan_event_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
nlmsg_free(msg);
return;
}
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 7e3821d..fb304ce9 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -16,7 +16,7 @@ struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, bool aborted);
void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
struct sk_buff *msg);
-void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
+void nl80211_send_scan_event(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u32 cmd);
void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
struct net_device *netdev);
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 8bd8290..327b23c 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -327,7 +327,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
return err;
}
- nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED);
+ nl80211_send_scan_event(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED);
RCU_INIT_POINTER(rdev->sched_scan_req, NULL);
kfree_rcu(sched_scan_req, rcu_head);
@@ -1108,7 +1108,7 @@ struct cfg80211_bss *
else
rcu_assign_pointer(tmp.pub.beacon_ies, ies);
rcu_assign_pointer(tmp.pub.ies, ies);
-
+
memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
tmp.pub.channel = channel;
tmp.pub.scan_width = data->scan_width;
--
1.9.1
^ 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