Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: 3.7.8/amd64 full interrupt hangs due to iwlwifi under big nfs copies out
From: Eric Dumazet @ 2013-06-18 16:52 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Marc MERLIN, David Miller, Larry.Finger, bhutchings,
	linux-wireless, netdev
In-Reply-To: <1361912099.8440.21.camel@jlt4.sipsolutions.net>

On Tue, 2013-02-26 at 21:54 +0100, Johannes Berg wrote:
> On Fri, 2013-02-22 at 22:14 -0800, Marc MERLIN wrote:
> > On Wed, Feb 20, 2013 at 10:15:03AM +0100, Johannes Berg wrote:
> > > On Wed, 2013-02-20 at 10:12 +0100, Johannes Berg wrote:
> > > > On Tue, 2013-02-19 at 08:21 -0800, Eric Dumazet wrote:
> > > > > On Tue, 2013-02-19 at 11:03 +0100, Johannes Berg wrote:
> > > > > > On Mon, 2013-02-18 at 21:17 -0800, Eric Dumazet wrote:
> > > > > > 
> > > > > > > > chrome: page allocation failure: order:1, mode:0x4020
> > > > > > > > Pid: 8730, comm: chrome Tainted: G           O 3.7.8-amd64-preempt-20121226-fixwd #1
> > > > > > > > Call Trace:
> > > > > > > >  <IRQ>  [<ffffffff810d5f38>] warn_alloc_failed+0x117/0x12c
> > > > > > 
> > > > > > > You could try to load iwlwifi with amsdu_size_8K set to 0 (disable)
> > > > > > > 
> > > > > > > It should hopefully use order-0 pages
> > > > > > 
> > > > > > It will, do that then, unfortunately it can't switch at runtime because
> > > > > > it advertised this support to the access point or clients.
> > > > > 
> > > > > What are the drawbacks of setting amsdu_size_8K to 0 by default ?
> > > > 
> > > > We're discussing this now, the only downside would be that we couldn't
> > > > receive 8k A-MSDUs. Thing is, practically nobody uses A-MSDU anyway, and
> > > > even when I suspect the difference between 4k and 8k won't be huge.
> > > 
> > > OTOH, this affects the protocol, and when you really can't allocate any
> > > order-1 pages you pointed out yourself that many other things also won't
> > > work, so I'm not really sure it makes a big difference if we change the
> > > driver?
> > 
> > That as an unscientific test, but when I did the NFS eats all my pages
> > test using ethernet, my system didn't hang like it did with iwlagn.
> > 
> > So while the NFS code is definitely doing something wrong when it uses
> > its default huge buffers, the e1000e code deals with it without hanging
> > my system.
> > 
> > So thanks for trying to improve the iwlagn code to avoid those system
> > lockups.
> 
> We'll be submitting a patch to make single pages default.

Do you think the same change would be possible for
drivers/net/wireless/iwlegacy/4965-mac.c ?

Thanks !



^ permalink raw reply

* Re: 3.7.8/amd64 full interrupt hangs due to iwlwifi under big nfs copies out
From: Johannes Berg @ 2013-06-18 17:04 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Marc MERLIN, David Miller, Larry.Finger, bhutchings,
	linux-wireless, netdev, sgruszka
In-Reply-To: <1371574361.3252.259.camel@edumazet-glaptop>

On Tue, 2013-06-18 at 09:52 -0700, Eric Dumazet wrote:

> > We'll be submitting a patch to make single pages default.
> 
> Do you think the same change would be possible for
> drivers/net/wireless/iwlegacy/4965-mac.c ?

Yes, Stanislaw?

johannes


^ permalink raw reply

* Re: [PATCHv2 4/5] mac80211: add channel switch command and beacon callbacks
From: Simon Wunderlich @ 2013-06-18 17:27 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Simon Wunderlich, linux-wireless, Simon Wunderlich,
	Mathias Kretschmer
In-Reply-To: <1371567628.8318.43.camel@jlt4.sipsolutions.net>

[-- Attachment #1: Type: text/plain, Size: 3817 bytes --]

Hey Johannes,

I'm skipping the "style" comments (you were right most of the time anyway) and will
only comment on the design stuff, see below:

On Tue, Jun 18, 2013 at 05:00:28PM +0200, Johannes Berg wrote:
> On Fri, 2013-06-14 at 14:15 +0200, Simon Wunderlich wrote:
> > @@ -2818,6 +2830,8 @@ struct ieee80211_ops {
> >  				 struct ieee80211_vif *vif,
> >  				 struct inet6_dev *idev);
> >  #endif
> > +	void (*channel_switch_beacon)(struct ieee80211_hw *hw,
> > +				      struct ieee80211_vif *vif);
> 
> What about channel contexts? Actually I don't really understand this?
> Shouldn't it say which channel to switch to?
> 

My first implementation (ath9k) does rely on mac80211 to complete the
channel switch, so it does not even need to know which channel is switched
to. I can add that as we can assume other drivers will behave differently ...

> >  /**
> > + * ieee80211_csa_finish - notify mac80211 about channel switch
> > + * @vif: &struct ieee80211_vif pointer from the add_interface callback.
> > + *
> > + * After a channel switch announcement was scheduled and the counter in this
> > + * announcement hit zero, this function must be called by the driver to
> > + * notify mac80211 that the channel can be changed.
> > + */
> > +void ieee80211_csa_finish(struct ieee80211_vif *vif);
> 
> If there are multiple interfaces, should it be called multiple times?
> etc. Maybe it should be on a channel context instead?
> 

Multiple interfaces are not supported - and I don't know how this should be
handled anyway. CSAs are triggered on a per-interface base from userspace,
and multiple CSAs would clash with each other (could be different channels,
different counters, etc ...).

Or would you have a suggestion how to handle this differently?

> > +	netif_carrier_off(sdata->dev);
> > +	err = ieee80211_vif_use_channel(sdata, &local->csa_chandef,
> > +					IEEE80211_CHANCTX_SHARED);
> > +	netif_carrier_on(sdata->dev);
> 
> That seems like a really bad idea, deleting a channel context might tear
> down all kinds of device state and might require deleting the interface
> first ... I think the chan context API needs to be extended to switch
> instead.
> 

Hm, yeah I can do that.

> > +	if (WARN_ON(err < 0))
> > +		return;
> 
> This can fail _easily_ too, e.g. if some other vif stays on the channel
> and you're now using too many channel contexts.
> 
> > +	/* don't handle if chanctx is used */
> > +	if (local->use_chanctx)
> > +		return -EBUSY;
> 
> Still don't really like the way you've implemented it :-)
> 

Why not? :)

> > +	vif->csa_active = 0;
> 
> is that a counter, or should it be a bool?

It should be bool.

> > +static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
> > +				 struct beacon_data *beacon)
> > +{
> > +	struct probe_resp *resp;
> > +	int counter_beacon = sdata->csa_counter_offset_beacon;
> > +	int counter_presp = sdata->csa_counter_offset_presp;
> > +
> > +	if (WARN_ON(counter_beacon > beacon->tail_len))
> > +		return;
> > +
> > +	if (WARN_ON(((u8 *)beacon->tail)[counter_beacon] == 0))
> > +		return;
> 
> How can these happen?
> 

Maybe when the beacon is re-assigned - although add a check for that
and remove these warnings ...

> > +	((u8 *)beacon->tail)[counter_beacon]--;
> > +
> > +	if (counter_presp && sdata->vif.type == NL80211_IFTYPE_AP) {
> > +		resp = rcu_dereference(sdata->u.ap.probe_resp);
> 
> Who guarantees RCU protection?
> 

Hmm ... should add that.

> > +		if (WARN_ON(!resp))
> > +			return;
> 
> That can legimitately happen, no? At least userspace is allowed to not
> set probe_resp now, if you want to change that ...
> 

If there is no presp then also counter_presp should not be set.

Cheers,
	Simon

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* [PATCH] rtlwifi: rtl8192cu: Fix duplicate if test
From: Larry Finger @ 2013-06-18 18:18 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Larry Finger, netdev, stable

A typo causes routine rtl92cu_phy_rf6052_set_cck_txpower() to test the
same condition twice. The problem was found using cppcheck-1.49, and the
proper fix was verified against the pre-mac80211 version of the code.

This patch was originally included as commit 1288aa4, but was accidentally
reverted in a later patch.

Reported-by: David Binderman <dcb314@hotmail.com> [original report]
Reported-by: Andrea Morello <andrea.merello@gmail.com> [report of accidental reversion]
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: stable <stable@kernel.org>  [back to 2.6.39]
---

John,

Although this patch is trivial and could be included in the 3.10 stream,
I think we should not burden DaveM nor Linus with it this late in the 3.10
cycle. Please push it into the 3.11 stream.

Thanks,

Larry
---
 drivers/net/wireless/rtlwifi/rtl8192cu/rf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
index 953f1a0..2119313 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
@@ -104,7 +104,7 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
 			tx_agc[RF90_PATH_A] = 0x10101010;
 			tx_agc[RF90_PATH_B] = 0x10101010;
 		} else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
-			   TXHIGHPWRLEVEL_LEVEL1) {
+			   TXHIGHPWRLEVEL_LEVEL2) {
 			tx_agc[RF90_PATH_A] = 0x00000000;
 			tx_agc[RF90_PATH_B] = 0x00000000;
 		} else{
-- 
1.8.1.4


^ permalink raw reply related

* Re: [PATCH] rtlwifi: rtl8192cu: Fix duplicate if test
From: Sergei Shtylyov @ 2013-06-18 18:24 UTC (permalink / raw)
  To: Larry Finger; +Cc: linville, linux-wireless, netdev, stable
In-Reply-To: <1371579497-5575-1-git-send-email-Larry.Finger@lwfinger.net>

Hello.

On 06/18/2013 10:18 PM, Larry Finger wrote:

> A typo causes routine rtl92cu_phy_rf6052_set_cck_txpower() to test the
> same condition twice. The problem was found using cppcheck-1.49, and the
> proper fix was verified against the pre-mac80211 version of the code.

> This patch was originally included as commit 1288aa4, but was accidentally

    You probably forgot to specify the summary line of that commit.

> reverted in a later patch.

> Reported-by: David Binderman <dcb314@hotmail.com> [original report]
> Reported-by: Andrea Morello <andrea.merello@gmail.com> [report of accidental reversion]
> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
> Cc: stable <stable@kernel.org>  [back to 2.6.39]

WBR, Sergei


^ permalink raw reply

* [PATCH V2] rtlwifi: rtl8192cu: Fix duplicate if test
From: Larry Finger @ 2013-06-18 18:25 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Larry Finger, netdev, stable

A typo causes routine rtl92cu_phy_rf6052_set_cck_txpower() to test the
same condition twice. The problem was found using cppcheck-1.49, and the
proper fix was verified against the pre-mac80211 version of the code.

This patch was originally included as commit 1288aa4, but was accidentally
reverted in a later patch.

Reported-by: David Binderman <dcb314@hotmail.com> [original report]
Reported-by: Andrea Morello <andrea.merello@gmail.com> [report of accidental reversion]
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: stable <stable@vger.kernel.org>  [back to 2.6.39]
---

John,

Although this patch is trivial and could be included in the 3.10 stream,
I think we should not burden DaveM nor Linus with it this late in the 3.10
cycle. Please push it into the 3.11 stream.

Thanks,

Larry
---

V2 - Fix error in stable mailing address
---
 drivers/net/wireless/rtlwifi/rtl8192cu/rf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
index 953f1a0..2119313 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
@@ -104,7 +104,7 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
 			tx_agc[RF90_PATH_A] = 0x10101010;
 			tx_agc[RF90_PATH_B] = 0x10101010;
 		} else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
-			   TXHIGHPWRLEVEL_LEVEL1) {
+			   TXHIGHPWRLEVEL_LEVEL2) {
 			tx_agc[RF90_PATH_A] = 0x00000000;
 			tx_agc[RF90_PATH_B] = 0x00000000;
 		} else{
-- 
1.8.1.4


^ permalink raw reply related

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

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

Pulling now (to wireless-next)...

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

^ permalink raw reply

* Re: pull request: TI wireless drivers 2013-06-18 (for 3.11)
From: John W. Linville @ 2013-06-18 18:45 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless
In-Reply-To: <1371552937.10702.15.camel@cumari.coelho.fi>

On Tue, Jun 18, 2013 at 01:55:37PM +0300, Luciano Coelho wrote:
> Hi John,
> 
> Here are a few patches intended for 3.11.  There's nothing major.  A
> bunch of bug fixes here and there, a hardware bug workaround and some
> small clean-ups.
> 
> Please let me know if you have any problems with it!
> 
> The following changes since commit 1105a13bb8ad29cf83d46989ee462d196038be87:
> 
>   orinoco_usb: fix memory leak in ezusb_access_ltv() when device disconnected (2013-06-14 13:37:16 -0400)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git for-linville
> 
> for you to fetch changes up to 789e90e567d7d93edc1b2001d17209c21cc37850:
> 
>   net: wireless: wl1251: Fix commenting style (2013-06-17 12:24:09 +0300)

Pulling now...

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

^ permalink raw reply

* Re: Lots of confusion on bss refcounting.
From: Ben Greear @ 2013-06-18 21:36 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <1371570723.22256.0.camel@jlt4.sipsolutions.net>

On 06/18/2013 08:52 AM, Johannes Berg wrote:
>
>>> You mean ->current_bss? That should be handled in all the callbacks in
>>> sme.c or so
>>
>> Looks like much of the action happens on work-queues.  I'm wondering if
>> we managed to delete wdev objects before we have completely cleaned up
>> in some cases...
>
> Don't we flush work structs appropriately?

I'm still seeing leaks after all those patches I posted...so I'm still
looking.  The leaked bss objects have a quite large refcount, in the
hundreds after an hour or so of running, so this is probably more than
a strange race somewhere.


This code looks questionable in wireless/mlme.c

int __cfg80211_mlme_assoc()
.....

It grabs a reference using cfg80211_get_bss, but it only
does a put on the reference if there was an error code.

The __cfg80211_mlme_auth a bit above always does a put on
the reference.

I'm thinking mlme_assoc should also always do put.  Any
reason you can think of otherwise?

Thanks,
Ben

>
> johannes
>


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


^ permalink raw reply

* [PATCH 1/6] wireless:  Add memory usage debugging.
From: greearb @ 2013-06-18 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear

From: Ben Greear <greearb@candelatech.com>

The bss objects are reference counted, and the ies
are also tricky to keep track of.  Add option to
track allocation and freeing of the ies and bss objects,
and add debugfs files to show the current objects.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 net/wireless/Kconfig   |   13 +++++
 net/wireless/core.c    |    5 +-
 net/wireless/core.h    |   17 ++++++
 net/wireless/debugfs.c |  117 ++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/debugfs.h |    2 +
 net/wireless/scan.c    |  127 ++++++++++++++++++++++++++++++++++++++++++------
 6 files changed, 264 insertions(+), 17 deletions(-)

diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 16d08b3..43ec2cd 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -115,6 +115,19 @@ config CFG80211_DEBUGFS
 
 	  If unsure, say N.
 
+config CFG80211_MEM_DEBUGGING
+	bool "cfg80211 memory debugging logic"
+	default n
+	depends on CFG80211_DEBUGFS
+	---help---
+	  Enable this if you want to debug memory handling for bss and ies
+	  objects.  New debugfs files: ieee80211/all_ies and all_bss will
+	  be created to display these objects.  This has a moderate CPU cost
+	  and uses a bit more memory than normal, but otherwise is not very
+	  expensive.
+
+	  If unsure, say N.
+
 config CFG80211_INTERNAL_REGDB
 	bool "use statically compiled regulatory rules database" if EXPERT
 	default n
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 9f08203..eb3e1de 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1123,6 +1123,7 @@ static int __init cfg80211_init(void)
 		goto out_fail_nl80211;
 
 	ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL);
+	ieee80211_debugfs_add_glbl(ieee80211_debugfs_dir);
 
 	err = regulatory_init();
 	if (err)
@@ -1137,7 +1138,7 @@ static int __init cfg80211_init(void)
 out_fail_wq:
 	regulatory_exit();
 out_fail_reg:
-	debugfs_remove(ieee80211_debugfs_dir);
+	debugfs_remove_recursive(ieee80211_debugfs_dir);
 out_fail_nl80211:
 	unregister_netdevice_notifier(&cfg80211_netdev_notifier);
 out_fail_notifier:
@@ -1151,7 +1152,7 @@ subsys_initcall(cfg80211_init);
 
 static void __exit cfg80211_exit(void)
 {
-	debugfs_remove(ieee80211_debugfs_dir);
+	debugfs_remove_recursive(ieee80211_debugfs_dir);
 	nl80211_exit();
 	unregister_netdevice_notifier(&cfg80211_netdev_notifier);
 	wiphy_sysfs_exit();
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 71b7285..e75be56 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -126,6 +126,23 @@ static inline void assert_cfg80211_lock(void)
 	lockdep_assert_held(&cfg80211_mutex);
 }
 
+#ifdef CONFIG_CFG80211_MEM_DEBUGGING
+
+struct wifi_mem_tracker {
+	struct list_head mylist;
+	char buf[40];
+	void *ptr;
+};
+extern struct list_head ies_list;
+extern spinlock_t ies_lock;
+extern atomic_t ies_count;
+
+extern struct list_head bss_list;
+extern spinlock_t bss_lock;
+extern atomic_t bss_count;
+
+#endif
+
 struct cfg80211_internal_bss {
 	struct list_head list;
 	struct list_head hidden_list;
diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c
index 920cabe..96dc757 100644
--- a/net/wireless/debugfs.c
+++ b/net/wireless/debugfs.c
@@ -31,6 +31,110 @@ static const struct file_operations name## _ops = {			\
 	.llseek = generic_file_llseek,					\
 };
 
+#define DEBUGFS_READONLY_FILE_OPS(name) \
+static const struct file_operations name## _ops = {			\
+	.read = name## _read,						\
+	.open = simple_open,						\
+	.llseek = generic_file_llseek,					\
+};
+
+#ifdef CONFIG_CFG80211_MEM_DEBUGGING
+static ssize_t all_ies_read(struct file *file, char __user *user_buf,
+				size_t count, loff_t *ppos)
+{
+	int mxln = 31500;
+	char *buf = kzalloc(mxln, GFP_KERNEL);
+	int q, res = 0;
+	struct wifi_mem_tracker *iesm;
+
+	if (!buf)
+		return 0;
+
+	spin_lock_bh(&ies_lock);
+	res += sprintf(buf + res, "Total: %i\n", atomic_read(&ies_count));
+	list_for_each_entry(iesm, &ies_list, mylist) {
+		res += sprintf(buf + res, "%p: %s\n",
+			       iesm->ptr, iesm->buf);
+		if (res >= mxln) {
+			res = mxln;
+			break;
+		}
+	}
+	spin_unlock_bh(&ies_lock);
+
+	q = simple_read_from_buffer(user_buf, count, ppos, buf, res);
+	kfree(buf);
+	return q;
+}
+
+static ssize_t all_bss_read(struct file *file, char __user *user_buf,
+			    size_t count, loff_t *ppos)
+{
+	int mxln = 31500;
+	char *buf = kzalloc(mxln, GFP_KERNEL);
+	int q, res = 0;
+	struct wifi_mem_tracker *bssm;
+
+	if (!buf)
+		return 0;
+
+	spin_lock_bh(&bss_lock);
+	res += sprintf(buf + res, "Total: %i\n", atomic_read(&bss_count));
+	list_for_each_entry(bssm, &bss_list, mylist) {
+		struct cfg80211_internal_bss *bss;
+		bss = (struct cfg80211_internal_bss *)(bssm->ptr);
+		res += sprintf(buf + res, "%p: #%lu %s\n",
+			       bssm->ptr, bss->refcount, bssm->buf);
+		if (res >= mxln) {
+			res = mxln;
+			break;
+		}
+	}
+	spin_unlock_bh(&bss_lock);
+
+	q = simple_read_from_buffer(user_buf, count, ppos, buf, res);
+	kfree(buf);
+	return q;
+}
+
+DEBUGFS_READONLY_FILE_OPS(all_ies);
+DEBUGFS_READONLY_FILE_OPS(all_bss);
+
+#endif
+
+static ssize_t bss_read(struct file *file, char __user *user_buf,
+			size_t count, loff_t *ppos)
+{
+	struct wiphy *wiphy = file->private_data;
+	struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
+	int mxln = 31500;
+	char *buf = kzalloc(mxln, GFP_KERNEL);
+	int q, res = 0;
+	struct cfg80211_internal_bss *bss;
+
+	if (!buf)
+		return 0;
+
+	spin_lock_bh(&dev->bss_lock);
+	list_for_each_entry(bss, &dev->bss_list, list) {
+		res += sprintf(buf + res,
+			       "%p: #%lu  bcn: %p  pr: %p  hidden: %p\n",
+			       bss, bss->refcount,
+			       rcu_access_pointer(bss->pub.beacon_ies),
+			       rcu_access_pointer(bss->pub.proberesp_ies),
+			       bss->pub.hidden_beacon_bss);
+		if (res >= mxln) {
+			res = mxln;
+			break;
+		}
+	}
+	spin_unlock_bh(&dev->bss_lock);
+
+	q = simple_read_from_buffer(user_buf, count, ppos, buf, res);
+	kfree(buf);
+	return q;
+}
+
 DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d",
 		      wiphy->rts_threshold)
 DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
@@ -39,6 +143,7 @@ DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d",
 		      wiphy->retry_short)
 DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
 		      wiphy->retry_long);
+DEBUGFS_READONLY_FILE_OPS(bss);
 
 static int ht_print_chan(struct ieee80211_channel *chan,
 			 char *buf, int buf_size, int offset)
@@ -112,4 +217,16 @@ void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev)
 	DEBUGFS_ADD(short_retry_limit);
 	DEBUGFS_ADD(long_retry_limit);
 	DEBUGFS_ADD(ht40allow_map);
+	DEBUGFS_ADD(bss);
+}
+
+#define DEBUGFS_ADD_GLBL(name)						\
+	debugfs_create_file(#name, S_IRUGO, dir, NULL, &name## _ops);
+
+void ieee80211_debugfs_add_glbl(struct dentry *dir)
+{
+#ifdef CONFIG_CFG80211_MEM_DEBUGGING
+	DEBUGFS_ADD_GLBL(all_ies);
+	DEBUGFS_ADD_GLBL(all_bss);
+#endif
 }
diff --git a/net/wireless/debugfs.h b/net/wireless/debugfs.h
index 74fdd38..f644869 100644
--- a/net/wireless/debugfs.h
+++ b/net/wireless/debugfs.h
@@ -3,9 +3,11 @@
 
 #ifdef CONFIG_CFG80211_DEBUGFS
 void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev);
+void ieee80211_debugfs_add_glbl(struct dentry *dir);
 #else
 static inline
 void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev) {}
+static inline void ieee80211_debugfs_add_glbl(struct dentry *dir) { }
 #endif
 
 #endif /* __CFG80211_DEBUGFS_H */
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index fd99ea4..542ff6d 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -57,6 +57,106 @@
 
 #define IEEE80211_SCAN_RESULT_EXPIRE	(30 * HZ)
 
+#ifdef CONFIG_CFG80211_MEM_DEBUGGING
+
+LIST_HEAD(ies_list);
+DEFINE_SPINLOCK(ies_lock);
+atomic_t ies_count = ATOMIC_INIT(0);
+
+LIST_HEAD(bss_list);
+DEFINE_SPINLOCK(bss_lock);
+atomic_t bss_count = ATOMIC_INIT(0);
+
+
+static void my_kfree_rcu_ies(struct cfg80211_bss_ies *ies)
+{
+	struct wifi_mem_tracker *iesm;
+	spin_lock_bh(&ies_lock);
+	list_for_each_entry(iesm, &ies_list, mylist) {
+		if (iesm->ptr == ies) {
+			list_del(&iesm->mylist);
+			kfree(iesm);
+			break;
+		}
+	}
+	spin_unlock_bh(&ies_lock);
+	atomic_sub(1, &ies_count);
+	kfree_rcu(ies, rcu_head);
+}
+
+#define my_kmalloc_ies(s, g)				\
+	_my_kmalloc_ies(s, g, __LINE__);
+
+static void* _my_kmalloc_ies(size_t s, gfp_t gfp, int l)
+{
+	void *rv = kmalloc(s, gfp);
+	if (rv) {
+		struct wifi_mem_tracker *iesm = kmalloc(sizeof(*iesm), gfp);
+		atomic_add(1, &ies_count);
+		if (iesm) {
+			snprintf(iesm->buf, sizeof(iesm->buf), "%i", l);
+			iesm->buf[sizeof(iesm->buf)-1] = 0;
+			iesm->ptr = rv;
+			INIT_LIST_HEAD(&iesm->mylist);
+			spin_lock_bh(&ies_lock);
+			list_add(&iesm->mylist, &ies_list);
+			spin_unlock_bh(&ies_lock);
+		} else {
+			pr_err("ERROR:  Could not allocate iesm.\n");
+		}
+	}
+	return rv;
+}
+
+static void my_kfree_bss(struct cfg80211_internal_bss *bss)
+{
+	struct wifi_mem_tracker *bssm;
+	spin_lock_bh(&bss_lock);
+	list_for_each_entry(bssm, &bss_list, mylist) {
+		if (bssm->ptr == bss) {
+			list_del(&bssm->mylist);
+			kfree(bssm);
+			break;
+		}
+	}
+	atomic_sub(1, &bss_count);
+	spin_unlock_bh(&bss_lock);
+	kfree(bss);
+}
+
+#define my_kzalloc_bss(s, g)				\
+	_my_kzalloc_bss(s, g, __LINE__);
+
+static void* _my_kzalloc_bss(size_t s, gfp_t gfp, int l)
+{
+	void *rv = kmalloc(s, gfp);
+	if (rv) {
+		struct wifi_mem_tracker *bssm = kmalloc(sizeof(*bssm), gfp);
+		atomic_add(1, &bss_count);
+		if (bssm) {
+			snprintf(bssm->buf, sizeof(bssm->buf), "%i", l);
+			bssm->buf[sizeof(bssm->buf)-1] = 0;
+			bssm->ptr = rv;
+			INIT_LIST_HEAD(&bssm->mylist);
+			spin_lock_bh(&bss_lock);
+			list_add(&bssm->mylist, &bss_list);
+			spin_unlock_bh(&bss_lock);
+		} else {
+			pr_err("ERROR:  Could not allocate bssm for bss.\n");
+		}
+	}
+	return rv;
+}
+
+#else
+
+#define my_kfree_rcu_ies(ies) kfree_rcu(ies, rcu_head)
+#define my_kmalloc_ies(s, g) kmalloc(s, g)
+#define my_kfree_bss(a) kfree(a)
+#define my_kzalloc_bss(s, g) kzalloc(s, g)
+
+#endif
+
 static void bss_free(struct cfg80211_internal_bss *bss)
 {
 	struct cfg80211_bss_ies *ies;
@@ -66,10 +166,10 @@ static void bss_free(struct cfg80211_internal_bss *bss)
 
 	ies = (void *)rcu_access_pointer(bss->pub.beacon_ies);
 	if (ies && !bss->pub.hidden_beacon_bss)
-		kfree_rcu(ies, rcu_head);
+		my_kfree_rcu_ies(ies);
 	ies = (void *)rcu_access_pointer(bss->pub.proberesp_ies);
 	if (ies)
-		kfree_rcu(ies, rcu_head);
+		my_kfree_rcu_ies(ies);
 
 	/*
 	 * This happens when the module is removed, it doesn't
@@ -78,7 +178,7 @@ static void bss_free(struct cfg80211_internal_bss *bss)
 	if (!list_empty(&bss->hidden_list))
 		list_del(&bss->hidden_list);
 
-	kfree(bss);
+	my_kfree_bss(bss);
 }
 
 static inline void bss_ref_get(struct cfg80211_registered_device *dev,
@@ -710,8 +810,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 			rcu_assign_pointer(found->pub.ies,
 					   tmp->pub.proberesp_ies);
 			if (old)
-				kfree_rcu((struct cfg80211_bss_ies *)old,
-					  rcu_head);
+				my_kfree_rcu_ies((struct cfg80211_bss_ies *)old);
 		} else if (rcu_access_pointer(tmp->pub.beacon_ies)) {
 			const struct cfg80211_bss_ies *old;
 			struct cfg80211_internal_bss *bss;
@@ -731,8 +830,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 				 */
 
 				f = rcu_access_pointer(tmp->pub.beacon_ies);
-				kfree_rcu((struct cfg80211_bss_ies *)f,
-					  rcu_head);
+				my_kfree_rcu_ies((struct cfg80211_bss_ies *)f);
 				goto drop;
 			}
 
@@ -759,8 +857,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 			}
 
 			if (old)
-				kfree_rcu((struct cfg80211_bss_ies *)old,
-					  rcu_head);
+				my_kfree_rcu_ies((struct cfg80211_bss_ies *)old);
 		}
 
 		found->pub.beacon_interval = tmp->pub.beacon_interval;
@@ -777,15 +874,15 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 		 * is allocated on the stack since it's not needed in the
 		 * more common case of an update
 		 */
-		new = kzalloc(sizeof(*new) + dev->wiphy.bss_priv_size,
-			      GFP_ATOMIC);
+		new = my_kzalloc_bss(sizeof(*new) + dev->wiphy.bss_priv_size,
+				     GFP_ATOMIC);
 		if (!new) {
 			ies = (void *)rcu_dereference(tmp->pub.beacon_ies);
 			if (ies)
-				kfree_rcu(ies, rcu_head);
+				my_kfree_rcu_ies(ies);
 			ies = (void *)rcu_dereference(tmp->pub.proberesp_ies);
 			if (ies)
-				kfree_rcu(ies, rcu_head);
+				my_kfree_rcu_ies(ies);
 			goto drop;
 		}
 		memcpy(new, tmp, sizeof(*new));
@@ -899,7 +996,7 @@ cfg80211_inform_bss(struct wiphy *wiphy,
 	 * override the IEs pointer should we have received an earlier
 	 * indication of Probe Response data.
 	 */
-	ies = kmalloc(sizeof(*ies) + ielen, gfp);
+	ies = my_kmalloc_ies(sizeof(*ies) + ielen, gfp);
 	if (!ies)
 		return NULL;
 	ies->len = ielen;
@@ -956,7 +1053,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
 	if (!channel)
 		return NULL;
 
-	ies = kmalloc(sizeof(*ies) + ielen, gfp);
+	ies = my_kmalloc_ies(sizeof(*ies) + ielen, gfp);
 	if (!ies)
 		return NULL;
 	ies->len = ielen;
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 2/6] mac80211:  Fix bss ref leak.
From: greearb @ 2013-06-18 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <1371593017-10985-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>

Some of the calls to ieee80211_destroy_assoc_data should
be putting the bss reference and were not.  Add boolean
argument to tell that method whether or not it should put
the reference and fix calling code appropriately.

Grab the bss reference where the pointer is assigned
to make it easier to properly do reference counting.

Also add some comments to help clarify the bss ref-counting
logic.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 net/mac80211/mlme.c |   33 ++++++++++++++++++++++++---------
 net/mac80211/scan.c |    6 ++++++
 2 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 6510790..622cdd8 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2400,7 +2400,7 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
 }
 
 static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
-					 bool assoc)
+					 bool assoc, bool put_bss)
 {
 	struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data;
 
@@ -2415,6 +2415,9 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
 		ieee80211_vif_release_channel(sdata);
 	}
 
+	if (put_bss)
+		cfg80211_put_bss(sdata->local->hw.wiphy, assoc_data->bss);
+
 	kfree(assoc_data);
 	sdata->u.mgd.assoc_data = NULL;
 }
@@ -2587,6 +2590,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
 	return true;
 }
 
+/** Calling code must dispose of bss reference if it is not NULL. */
 static enum rx_mgmt_action __must_check
 ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 			     struct ieee80211_mgmt *mgmt, size_t len,
@@ -2643,17 +2647,20 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 		return RX_MGMT_NONE;
 	}
 
+	/* bss will be passed back to calling code, and that code must
+	 * deal with properly putting the reference.
+	 */
 	*bss = assoc_data->bss;
 
 	if (status_code != WLAN_STATUS_SUCCESS) {
 		sdata_info(sdata, "%pM denied association (code=%d)\n",
 			   mgmt->sa, status_code);
-		ieee80211_destroy_assoc_data(sdata, false);
+		ieee80211_destroy_assoc_data(sdata, false, false);
 	} else {
 		if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {
 			/* oops -- internal error -- send timeout for now */
-			ieee80211_destroy_assoc_data(sdata, false);
-			cfg80211_put_bss(sdata->local->hw.wiphy, *bss);
+			ieee80211_destroy_assoc_data(sdata, false, true);
+			*bss = NULL; /* Ensure no stale references */
 			return RX_MGMT_CFG80211_ASSOC_TIMEOUT;
 		}
 		sdata_info(sdata, "associated\n");
@@ -2663,7 +2670,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 		 * recalc after assoc_data is NULL but before associated
 		 * is set can cause the interface to go idle
 		 */
-		ieee80211_destroy_assoc_data(sdata, true);
+		ieee80211_destroy_assoc_data(sdata, true, false);
 	}
 
 	return RX_MGMT_CFG80211_RX_ASSOC;
@@ -3105,6 +3112,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 		break;
 	case IEEE80211_STYPE_ASSOC_RESP:
 	case IEEE80211_STYPE_REASSOC_RESP:
+		/* One way or another, must eventually put bss reference
+		 * if it is not NULL.
+		 */
 		rma = ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, &bss);
 		break;
 	case IEEE80211_STYPE_ACTION:
@@ -3136,6 +3146,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 		cfg80211_send_rx_assoc(sdata->dev, bss, (u8 *)mgmt, skb->len);
 		break;
 	case RX_MGMT_CFG80211_ASSOC_TIMEOUT:
+		/* bss reference is already put at this point, see
+		 * 'internal-error' comment in ieee80211_rx_mgmt_assoc_resp
+		 */
 		cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid);
 		break;
 	case RX_MGMT_CFG80211_TX_DEAUTH:
@@ -3385,7 +3398,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
 
 			memcpy(bssid, ifmgd->assoc_data->bss->bssid, ETH_ALEN);
 
-			ieee80211_destroy_assoc_data(sdata, false);
+			ieee80211_destroy_assoc_data(sdata, false, true);
 
 			mutex_unlock(&ifmgd->mtx);
 			cfg80211_send_assoc_timeout(sdata->dev, bssid);
@@ -3935,6 +3948,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 		return -ENOMEM;
 
 	auth_data->bss = req->bss;
+	cfg80211_ref_bss(local->hw.wiphy, auth_data->bss);
 
 	if (req->sae_data_len >= 4) {
 		__le16 *pos = (__le16 *) req->sae_data;
@@ -3998,8 +4012,6 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 		goto err_clear;
 	}
 
-	/* hold our own reference */
-	cfg80211_ref_bss(local->hw.wiphy, auth_data->bss);
 	err = 0;
 	goto out_unlock;
 
@@ -4008,6 +4020,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
 	ifmgd->auth_data = NULL;
  err_free:
+	cfg80211_put_bss(sdata->local->hw.wiphy, auth_data->bss);
 	kfree(auth_data);
  out_unlock:
 	mutex_unlock(&ifmgd->mtx);
@@ -4129,6 +4142,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 	}
 
 	assoc_data->bss = req->bss;
+	cfg80211_ref_bss(sdata->local->hw.wiphy, assoc_data->bss);
 
 	if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) {
 		if (ifmgd->powersave)
@@ -4259,6 +4273,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
  err_clear:
 	memset(ifmgd->bssid, 0, ETH_ALEN);
 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
+	cfg80211_put_bss(sdata->local->hw.wiphy, assoc_data->bss);
 	ifmgd->assoc_data = NULL;
  err_free:
 	kfree(assoc_data);
@@ -4364,7 +4379,7 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
 
 	mutex_lock(&ifmgd->mtx);
 	if (ifmgd->assoc_data)
-		ieee80211_destroy_assoc_data(sdata, false);
+		ieee80211_destroy_assoc_data(sdata, false, true);
 	if (ifmgd->auth_data)
 		ieee80211_destroy_auth_data(sdata, false);
 	del_timer_sync(&ifmgd->timer);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 0b6434b..e0fcb4a 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -55,6 +55,9 @@ static bool is_uapsd_supported(struct ieee802_11_elems *elems)
 	return qos_info & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD;
 }
 
+/** Must (eventually) put the returned value to keep from leaking
+ * a reference to the bss.
+ */
 struct ieee80211_bss *
 ieee80211_bss_info_update(struct ieee80211_local *local,
 			  struct ieee80211_rx_status *rx_status,
@@ -73,6 +76,9 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
 	else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
 		signal = (rx_status->signal * 100) / local->hw.max_signal;
 
+	/* We now own a reference to cbss, have to make sure we
+	 * put it later.
+	 */
 	cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel,
 					 mgmt, len, signal, GFP_ATOMIC);
 	if (!cbss)
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 6/6] wireless:  Add comments about bss refcounting.
From: greearb @ 2013-06-18 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <1371593017-10985-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>

Should help the next person that tries to understand
the bss refcounting logic.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 net/wireless/scan.c |    4 ++++
 net/wireless/sme.c  |    3 +++
 2 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 542ff6d..834d2f9 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -622,6 +622,7 @@ static int cmp_bss(struct cfg80211_bss *a,
 	}
 }
 
+/** Returned bss is reference counted and must be cleaned up appropriately. */
 struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
 				      struct ieee80211_channel *channel,
 				      const u8 *bssid,
@@ -777,6 +778,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev,
 	return true;
 }
 
+/** Returned bss is reference counted and must be cleaned up appropriately. */
 static struct cfg80211_internal_bss *
 cfg80211_bss_update(struct cfg80211_registered_device *dev,
 		    struct cfg80211_internal_bss *tmp)
@@ -962,6 +964,7 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
 	return channel;
 }
 
+/** Returned bss is reference counted and must be cleaned up appropriately. */
 struct cfg80211_bss*
 cfg80211_inform_bss(struct wiphy *wiphy,
 		    struct ieee80211_channel *channel,
@@ -1019,6 +1022,7 @@ cfg80211_inform_bss(struct wiphy *wiphy,
 }
 EXPORT_SYMBOL(cfg80211_inform_bss);
 
+/** Returned bss is reference counted and must be cleaned up appropriately. */
 struct cfg80211_bss *
 cfg80211_inform_bss_frame(struct wiphy *wiphy,
 			  struct ieee80211_channel *channel,
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index ea2ce33..d26cd68 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -263,6 +263,7 @@ void cfg80211_conn_work(struct work_struct *work)
 	rtnl_unlock();
 }
 
+/** Returned bss is reference counted and must be cleaned up appropriately. */
 static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
 {
 	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -579,6 +580,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 }
 EXPORT_SYMBOL(cfg80211_connect_result);
 
+/** Consumes bss object one way or another */
 void __cfg80211_roamed(struct wireless_dev *wdev,
 		       struct cfg80211_bss *bss,
 		       const u8 *req_ie, size_t req_ie_len,
@@ -662,6 +664,7 @@ void cfg80211_roamed(struct net_device *dev,
 }
 EXPORT_SYMBOL(cfg80211_roamed);
 
+/** Consumes bss object one way or another */
 void cfg80211_roamed_bss(struct net_device *dev,
 			 struct cfg80211_bss *bss, const u8 *req_ie,
 			 size_t req_ie_len, const u8 *resp_ie,
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 3/6] wireless:  Make sure __cfg80211_connect_result always puts bss.
From: greearb @ 2013-06-18 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <1371593017-10985-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>

Otherwise, we can leak a bss reference.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 net/wireless/sme.c |   11 +++++++++--
 1 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 6066720..ea2ce33 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -420,6 +420,7 @@ void cfg80211_sme_failed_assoc(struct wireless_dev *wdev)
 	schedule_work(&rdev->conn_work);
 }
 
+/** This method must consume bss one way or another */
 void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 			       const u8 *req_ie, size_t req_ie_len,
 			       const u8 *resp_ie, size_t resp_ie_len,
@@ -435,11 +436,17 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 	ASSERT_WDEV_LOCK(wdev);
 
 	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
-		    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
+		    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) {
+		if (bss)
+			cfg80211_put_bss(wdev->wiphy, bss);
 		return;
+	}
 
-	if (wdev->sme_state != CFG80211_SME_CONNECTING)
+	if (wdev->sme_state != CFG80211_SME_CONNECTING) {
+		if (bss)
+			cfg80211_put_bss(wdev->wiphy, bss);
 		return;
+	}
 
 	nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
 				    bssid, req_ie, req_ie_len,
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 4/6] wireless:  Check for dangling wdev->current_bss pointer.
From: greearb @ 2013-06-18 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <1371593017-10985-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>

If it *is* still set when the netdev is being deleted,
then we are about to leak a pointer.  Warn and clean up
in that case.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 net/wireless/core.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index eb3e1de..9e05da9 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1063,6 +1063,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 		 * freed.
 		 */
 		cfg80211_process_wdev_events(wdev);
+
+		if (WARN_ON(wdev->current_bss)) {
+			cfg80211_unhold_bss(wdev->current_bss);
+			cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
+			SET_BSS(wdev, NULL);
+		}
 		break;
 	case NETDEV_PRE_UP:
 		if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 5/6] wireless:  Fix bss ref count leak in __cfg80211_mlme_assoc
From: greearb @ 2013-06-18 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <1371593017-10985-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>

The rdev_assoc path holds it's own reference, so the
mlme_assoc must release the reference it took earlier
before returning.

This actually appears to be the leak I have been seeing
in my tests.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 net/wireless/mlme.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index d975510..1c60268 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -432,8 +432,8 @@ out:
 	if (err) {
 		if (was_connected)
 			SET_SME_STATE(wdev, CFG80211_SME_CONNECTED);
-		cfg80211_put_bss(&rdev->wiphy, req.bss);
 	}
+	cfg80211_put_bss(&rdev->wiphy, req.bss);
 
 	return err;
 }
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 2/3] mwifiex: add basic 11h support for station
From: Bing Zhao @ 2013-06-18 23:36 UTC (permalink / raw)
  To: linux-wireless
  Cc: John W. Linville, Amitkumar Karwar, Avinash Patil,
	Yogesh Ashok Powar, Nishant Sarmukadam, Frank Huang, Bing Zhao,
	Paul Stewart
In-Reply-To: <1371598618-26593-1-git-send-email-bzhao@marvell.com>

From: Amitkumar Karwar <akarwar@marvell.com>

This patch adds code to parse requested AP's 11h capabilities
and add 11h information in association request.

Also, deauth is sent to the AP after receiving channel switch
announcement event from firmware. This happens when AP advertises
WLAN_EID_CHANNEL_SWITCH IE in it's beacon.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: Paul Stewart <pstew@chromium.org>
---
 drivers/net/wireless/mwifiex/11h.c       | 101 +++++++++++++++++++++++++++++++
 drivers/net/wireless/mwifiex/Makefile    |   1 +
 drivers/net/wireless/mwifiex/fw.h        |  14 +++++
 drivers/net/wireless/mwifiex/join.c      |   2 +
 drivers/net/wireless/mwifiex/main.h      |   7 +++
 drivers/net/wireless/mwifiex/scan.c      |  19 ++++++
 drivers/net/wireless/mwifiex/sta_event.c |   7 +++
 drivers/net/wireless/mwifiex/sta_ioctl.c |   3 +
 8 files changed, 154 insertions(+)
 create mode 100644 drivers/net/wireless/mwifiex/11h.c

diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c
new file mode 100644
index 0000000..8d68307
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11h.c
@@ -0,0 +1,101 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11h
+ *
+ * Copyright (C) 2013, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "main.h"
+#include "fw.h"
+
+
+/* This function appends 11h info to a buffer while joining an
+ * infrastructure BSS
+ */
+static void
+mwifiex_11h_process_infra_join(struct mwifiex_private *priv, u8 **buffer,
+			       struct mwifiex_bssdescriptor *bss_desc)
+{
+	struct mwifiex_ie_types_header *ie_header;
+	struct mwifiex_ie_types_pwr_capability *cap;
+	struct mwifiex_ie_types_local_pwr_constraint *constraint;
+	struct ieee80211_supported_band *sband;
+	u8 radio_type;
+	int i;
+
+	if (!buffer || !(*buffer))
+		return;
+
+	radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
+	sband = priv->wdev->wiphy->bands[radio_type];
+
+	cap = (struct mwifiex_ie_types_pwr_capability *)*buffer;
+	cap->header.type = cpu_to_le16(WLAN_EID_PWR_CAPABILITY);
+	cap->header.len = cpu_to_le16(2);
+	cap->min_pwr = 0;
+	cap->max_pwr = 0;
+	*buffer += sizeof(*cap);
+
+	constraint = (struct mwifiex_ie_types_local_pwr_constraint *)*buffer;
+	constraint->header.type = cpu_to_le16(WLAN_EID_PWR_CONSTRAINT);
+	constraint->header.len = cpu_to_le16(2);
+	constraint->chan = bss_desc->channel;
+	constraint->constraint = bss_desc->local_constraint;
+	*buffer += sizeof(*constraint);
+
+	ie_header = (struct mwifiex_ie_types_header *)*buffer;
+	ie_header->type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+	ie_header->len  = cpu_to_le16(2 * sband->n_channels + 2);
+	*buffer += sizeof(*ie_header);
+	*(*buffer)++ = WLAN_EID_SUPPORTED_CHANNELS;
+	*(*buffer)++ = 2 * sband->n_channels;
+	for (i = 0; i < sband->n_channels; i++) {
+		*(*buffer)++ = ieee80211_frequency_to_channel(
+					sband->channels[i].center_freq);
+		*(*buffer)++ = 1; /* one channel in the subband */
+	}
+}
+
+/* Enable or disable the 11h extensions in the firmware */
+static int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag)
+{
+	u32 enable = flag;
+
+	return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
+				     HostCmd_ACT_GEN_SET, DOT11H_I, &enable);
+}
+
+/* This functions processes TLV buffer for a pending BSS Join command.
+ *
+ * Activate 11h functionality in the firmware if the spectrum management
+ * capability bit is found in the network we are joining. Also, necessary
+ * TLVs are set based on requested network's 11h capability.
+ */
+void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
+			      struct mwifiex_bssdescriptor *bss_desc)
+{
+	if (bss_desc->sensed_11h) {
+		/* Activate 11h functions in firmware, turns on capability
+		 * bit
+		 */
+		mwifiex_11h_activate(priv, true);
+		bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_SPECTRUM_MGMT;
+		mwifiex_11h_process_infra_join(priv, buffer, bss_desc);
+	} else {
+		/* Deactivate 11h functions in the firmware */
+		mwifiex_11h_activate(priv, false);
+		bss_desc->cap_info_bitmap &= ~WLAN_CAPABILITY_SPECTRUM_MGMT;
+	}
+}
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
index ecf2846..a42a506 100644
--- a/drivers/net/wireless/mwifiex/Makefile
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -40,6 +40,7 @@ mwifiex-y += sta_rx.o
 mwifiex-y += uap_txrx.o
 mwifiex-y += cfg80211.o
 mwifiex-y += ethtool.o
+mwifiex-y += 11h.o
 mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
 obj-$(CONFIG_MWIFIEX) += mwifiex.o
 
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index d6ada73..b6fbbf6 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -438,6 +438,7 @@ enum P2P_MODES {
 #define EVENT_BW_CHANGE                 0x00000048
 #define EVENT_UAP_MIC_COUNTERMEASURES   0x0000004c
 #define EVENT_HOSTWAKE_STAIE		0x0000004d
+#define EVENT_CHANNEL_SWITCH_ANN        0x00000050
 #define EVENT_REMAIN_ON_CHAN_EXPIRED    0x0000005f
 
 #define EVENT_ID_MASK                   0xffff
@@ -975,6 +976,7 @@ enum SNMP_MIB_INDEX {
 	LONG_RETRY_LIM_I = 7,
 	FRAG_THRESH_I = 8,
 	DOT11D_I = 9,
+	DOT11H_I = 10,
 };
 
 #define MAX_SNMP_BUF_SIZE   128
@@ -1206,6 +1208,18 @@ struct host_cmd_ds_sta_deauth {
 	__le16 reason;
 } __packed;
 
+struct mwifiex_ie_types_pwr_capability {
+	struct mwifiex_ie_types_header header;
+	s8 min_pwr;
+	s8 max_pwr;
+};
+
+struct mwifiex_ie_types_local_pwr_constraint {
+	struct mwifiex_ie_types_header header;
+	u8 chan;
+	u8 constraint;
+};
+
 struct mwifiex_ie_types_wmm_param_set {
 	struct mwifiex_ie_types_header header;
 	u8 wmm_ie[1];
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 122175a..1c8a771 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -534,6 +534,8 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
 
 	mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc);
 
+	mwifiex_11h_process_join(priv, &pos, bss_desc);
+
 	cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN);
 
 	/* Set the Capability info at last */
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 0832c24..95a6f52 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -309,6 +309,9 @@ struct mwifiex_bssdescriptor {
 	u16 wapi_offset;
 	u8 *beacon_buf;
 	u32 beacon_buf_size;
+	u8 sensed_11h;
+	u8 local_constraint;
+	u8 chan_sw_ie_present;
 };
 
 struct mwifiex_current_bss_params {
@@ -1119,6 +1122,10 @@ u8 *mwifiex_11d_code_2_region(u8 code);
 void mwifiex_uap_del_sta_data(struct mwifiex_private *priv,
 			      struct mwifiex_sta_node *node);
 
+void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
+			      struct mwifiex_bssdescriptor *bss_desc);
+int mwifiex_11h_handle_event_chanswann(struct mwifiex_private *priv);
+
 extern const struct ethtool_ops mwifiex_ethtool_ops;
 
 #ifdef CONFIG_DEBUG_FS
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 801b6b7..284d68b 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -391,6 +391,12 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
 		return 0;
 	}
 
+	if (bss_desc->chan_sw_ie_present) {
+		dev_err(adapter->dev,
+			"Don't connect to AP with WLAN_EID_CHANNEL_SWITCH\n");
+		return -1;
+	}
+
 	if (mwifiex_is_bss_wapi(priv, bss_desc)) {
 		dev_dbg(adapter->dev, "info: return success for WAPI AP\n");
 		return 0;
@@ -1169,6 +1175,19 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
 			bss_entry->erp_flags = *(current_ptr + 2);
 			break;
 
+		case WLAN_EID_PWR_CONSTRAINT:
+			bss_entry->local_constraint = *(current_ptr + 2);
+			bss_entry->sensed_11h = true;
+			break;
+
+		case WLAN_EID_CHANNEL_SWITCH:
+			bss_entry->chan_sw_ie_present = true;
+		case WLAN_EID_PWR_CAPABILITY:
+		case WLAN_EID_TPC_REPORT:
+		case WLAN_EID_QUIET:
+			bss_entry->sensed_11h = true;
+		    break;
+
 		case WLAN_EID_EXT_SUPP_RATES:
 			/*
 			 * Only process extended supported rate
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index 41aafc7..0f7b4cf 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -427,6 +427,13 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 
 		break;
 
+	case EVENT_CHANNEL_SWITCH_ANN:
+		dev_dbg(adapter->dev, "event: Channel Switch Announcement\n");
+		ret = mwifiex_send_cmd_async(priv,
+			HostCmd_CMD_802_11_DEAUTHENTICATE,
+			HostCmd_ACT_GEN_SET, 0,
+			priv->curr_bss_params.bss_descriptor.mac_address);
+
 	default:
 		dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
 			eventcause);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 15b5457..498add7 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -178,6 +178,9 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
 	 */
 	bss_desc->disable_11ac = true;
 
+	if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT)
+		bss_desc->sensed_11h = true;
+
 	return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
 }
 
-- 
1.8.2.3


^ permalink raw reply related

* [PATCH 3/3] mwifiex: channel switch handling for station
From: Bing Zhao @ 2013-06-18 23:36 UTC (permalink / raw)
  To: linux-wireless
  Cc: John W. Linville, Amitkumar Karwar, Avinash Patil,
	Yogesh Ashok Powar, Nishant Sarmukadam, Frank Huang, Bing Zhao,
	Paul Stewart
In-Reply-To: <1371598618-26593-1-git-send-email-bzhao@marvell.com>

From: Amitkumar Karwar <akarwar@marvell.com>

After receiving channel switch announcement from AP, scan and
association on that channel is blocked for DFS_CHAN_MOVE_TIME
(10 seconds). Hence station will be able to connect to the AP,
once it is moved to new channel.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: Paul Stewart <pstew@chromium.org>
---
 drivers/net/wireless/mwifiex/fw.h        |  2 ++
 drivers/net/wireless/mwifiex/init.c      |  3 +++
 drivers/net/wireless/mwifiex/main.h      | 20 ++++++++++++++++++++
 drivers/net/wireless/mwifiex/scan.c      | 18 ++++++++++++++++++
 drivers/net/wireless/mwifiex/sta_event.c |  3 +++
 drivers/net/wireless/mwifiex/sta_ioctl.c |  8 ++++++++
 6 files changed, 54 insertions(+)

diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index b6fbbf6..1b45aa5 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -245,6 +245,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define HT_BW_20    0
 #define HT_BW_40    1
 
+#define DFS_CHAN_MOVE_TIME      10000
+
 #define HostCmd_CMD_GET_HW_SPEC                       0x0003
 #define HostCmd_CMD_802_11_SCAN                       0x0006
 #define HostCmd_CMD_802_11_GET_LOG                    0x000b
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 2fe31dc..caaf4bd 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -133,6 +133,9 @@ int mwifiex_init_priv(struct mwifiex_private *priv)
 
 	priv->scan_block = false;
 
+	priv->csa_chan = 0;
+	priv->csa_expire_time = 0;
+
 	return mwifiex_add_bss_prio_tbl(priv);
 }
 
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 95a6f52..3da73d3 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -513,6 +513,8 @@ struct mwifiex_private {
 	u32 mgmt_frame_mask;
 	struct mwifiex_roc_cfg roc_cfg;
 	bool scan_aborting;
+	u8 csa_chan;
+	unsigned long csa_expire_time;
 };
 
 enum mwifiex_ba_status {
@@ -1021,6 +1023,24 @@ static inline bool mwifiex_is_skb_mgmt_frame(struct sk_buff *skb)
 	return (*(u32 *)skb->data == PKT_TYPE_MGMT);
 }
 
+/* This function retrieves channel closed for operation by Channel
+ * Switch Announcement.
+ */
+static inline u8
+mwifiex_11h_get_csa_closed_channel(struct mwifiex_private *priv)
+{
+	if (!priv->csa_chan)
+		return 0;
+
+	/* Clear csa channel, if DFS channel move time has passed */
+	if (jiffies > priv->csa_expire_time) {
+		priv->csa_chan = 0;
+		priv->csa_expire_time = 0;
+	}
+
+	return priv->csa_chan;
+}
+
 int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
 			     u32 func_init_shutdown);
 int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8);
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 284d68b..c447d9b 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -575,6 +575,9 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
 		return -1;
 	}
 
+	/* Check csa channel expiry before preparing scan list */
+	mwifiex_11h_get_csa_closed_channel(priv);
+
 	chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
 
 	/* Set the temp channel struct pointer to the start of the desired
@@ -604,6 +607,11 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
 		while (tlv_idx < max_chan_per_scan &&
 		       tmp_chan_list->chan_number && !done_early) {
 
+			if (tmp_chan_list->chan_number == priv->csa_chan) {
+				tmp_chan_list++;
+				continue;
+			}
+
 			dev_dbg(priv->adapter->dev,
 				"info: Scan: Chan(%3d), Radio(%d),"
 				" Mode(%d, %d), Dur(%d)\n",
@@ -1594,6 +1602,9 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 		goto check_next_scan;
 	}
 
+	/* Check csa channel expiry before parsing scan response */
+	mwifiex_11h_get_csa_closed_channel(priv);
+
 	bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
 	dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n",
 		bytes_left);
@@ -1746,6 +1757,13 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 			struct ieee80211_channel *chan;
 			u8 band;
 
+			/* Skip entry if on csa closed channel */
+			if (channel == priv->csa_chan) {
+				dev_dbg(adapter->dev,
+					"Dropping entry on csa closed channel\n");
+				continue;
+			}
+
 			band = BAND_G;
 			if (chan_band_tlv) {
 				chan_band =
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index 0f7b4cf..8155471 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -429,6 +429,9 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 
 	case EVENT_CHANNEL_SWITCH_ANN:
 		dev_dbg(adapter->dev, "event: Channel Switch Announcement\n");
+		priv->csa_expire_time =
+				jiffies + msecs_to_jiffies(DFS_CHAN_MOVE_TIME);
+		priv->csa_chan = priv->curr_bss_params.bss_descriptor.channel;
 		ret = mwifiex_send_cmd_async(priv,
 			HostCmd_CMD_802_11_DEAUTHENTICATE,
 			HostCmd_ACT_GEN_SET, 0,
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 498add7..206c3e0 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -281,6 +281,14 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
 		if (ret)
 			goto done;
 
+		if (mwifiex_11h_get_csa_closed_channel(priv) ==
+							(u8)bss_desc->channel) {
+			dev_err(adapter->dev,
+				"Attempt to reconnect on csa closed chan(%d)\n",
+				bss_desc->channel);
+			goto done;
+		}
+
 		dev_dbg(adapter->dev, "info: SSID found in scan list ... "
 				      "associating...\n");
 
-- 
1.8.2.3


^ permalink raw reply related

* [PATCH 1/3] mwifiex: code rearrangement for better readability
From: Bing Zhao @ 2013-06-18 23:36 UTC (permalink / raw)
  To: linux-wireless
  Cc: John W. Linville, Amitkumar Karwar, Avinash Patil,
	Yogesh Ashok Powar, Nishant Sarmukadam, Frank Huang, Bing Zhao

From: Amitkumar Karwar <akarwar@marvell.com>

Use negative check (if(!bss_desc)) and return failure
instead of failing a NULL check later in
mwifiex_check_network_compatibility() routine.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
---
 drivers/net/wireless/mwifiex/sta_ioctl.c | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 23aa910..15b5457 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -255,25 +255,24 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
 	}
 
 	if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+		u8 config_bands;
+
 		/* Infra mode */
 		ret = mwifiex_deauthenticate(priv, NULL);
 		if (ret)
 			goto done;
 
-		if (bss_desc) {
-			u8 config_bands = 0;
+		if (!bss_desc)
+			return -1;
 
-			if (mwifiex_band_to_radio_type((u8) bss_desc->bss_band)
-			    == HostCmd_SCAN_RADIO_TYPE_BG)
-				config_bands = BAND_B | BAND_G | BAND_GN |
-					       BAND_GAC;
-			else
-				config_bands = BAND_A | BAND_AN | BAND_AAC;
+		if (mwifiex_band_to_radio_type(bss_desc->bss_band) ==
+						HostCmd_SCAN_RADIO_TYPE_BG)
+			config_bands = BAND_B | BAND_G | BAND_GN | BAND_GAC;
+		else
+			config_bands = BAND_A | BAND_AN | BAND_AAC;
 
-			if (!((config_bands | adapter->fw_bands) &
-			      ~adapter->fw_bands))
-				adapter->config_bands = config_bands;
-		}
+		if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands))
+			adapter->config_bands = config_bands;
 
 		ret = mwifiex_check_network_compatibility(priv, bss_desc);
 		if (ret)
-- 
1.8.2.3


^ permalink raw reply related

* Association status 5 from Netgear
From: Ben Greear @ 2013-06-19  0:28 UTC (permalink / raw)
  To: linux-wireless@vger.kernel.org

I'm seeing association status code 5 coming from an over-loaded
netgear.

I'm guessing that the AP is buggy and is trying to use a reason-code for
a status-code?

A reason-code of 5 would make sense here:
"Disassociated because AP is unable to handle all currently associated STAs"

(per 802.11-2012, pages 442, 445)

# grep sta325 /tmp/iwlog.txt
sta325 (phy #3): scan started
sta325: new station c4:3d:c7:af:3c:7c
sta325 (phy #3): scan finished: 5745, ""
sta325 (phy #3): auth c4:3d:c7:af:3c:7c -> 00:1d:ea:be:ef:7c status: 0: Successful
sta325: del station c4:3d:c7:af:3c:7c
sta325 (phy #3): assoc c4:3d:c7:af:3c:7c -> 00:1d:ea:be:ef:7c status: 5: <unknown>
sta325 (phy #3): failed to connect to c4:3d:c7:af:3c:7c, status: 5: <unknown>

Thanks,
Ben

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


^ permalink raw reply

* nl80211 NULL pointer dereference
From: Linus Torvalds @ 2013-06-19  1:46 UTC (permalink / raw)
  To: Johannes Berg, John W. Linville, David S. Miller
  Cc: Linux Wireless List, Network Development

Hmm. Maybe this is old, but I don't think I've seen it before (who
knows, maybe it has killed the machine before, I had a hard hang the
other day).

It's a NULL pointer dereference in nl80211_set_reg() on my Pixel. The
machine kind of stayed up afterwards, although with no working
wireless, and it would not shut down cleanly presumably due to locks
held etc.

Any ideas? I'm including the few wireless-related messages that
happened justr before the oops. Being a pixel, this is with the ath9k
driver.

                     Linus

---
  wlp1s0: authenticate with 00:c0:23:ba:27:40
  wlp1s0: send auth to 00:c0:23:ba:27:40 (try 1/3)
  wlp1s0: authenticated
  ath9k 0000:01:00.0 wlp1s0: disabling HT as WMM/QoS is not supported by the AP
  ath9k 0000:01:00.0 wlp1s0: disabling VHT as WMM/QoS is not supported by the AP
  wlp1s0: associate with 00:c0:23:ba:27:40 (try 1/3)
  wlp1s0: RX AssocResp from 00:c0:23:ba:27:40 (capab=0x501 status=0 aid=4)
  wlp1s0: associated
  cfg80211: Calling CRDA for country: US

  BUG: unable to handle kernel NULL pointer dereference at           (null)
  IP: [<ffffffffa02a77d3>] nl80211_set_reg+0x113/0x2c0 [cfg80211]
  PGD 1459c3067 PUD 10f6fa067 PMD 0
  Oops: 0000 [#1] SMP
  Modules linked in: ftdi_sio tpm_tis tpm tpm_bios usb_storage fuse
ebtable_nat nf_conntrack_netbios_ns nf_conntrack_broadcast
ipt_MASQUERADE ip6table_nat nf_nat_ipv6 ip6table_mangle ip6t_REJECT
nf_conntra
   media chromeos_laptop snd_timer snd microcode lpc_ich rfkill
soundcore mfd_core i2c_i801 uinput binfmt_misc dm_crypt i915
i2c_algo_bit drm_kms_helper drm crc32_pclmul crc32c_intel
ghash_clmulni_intel i2
  CPU: 1 PID: 4859 Comm: crda Not tainted 3.10.0-rc6 #2
  Hardware name: GOOGLE Link, BIOS          12/10/2012
  RIP: 0010:[<ffffffffa02a77d3>]  [<ffffffffa02a77d3>]
nl80211_set_reg+0x113/0x2c0 [cfg80211]
  RSP: 0018:ffff8801277779f0  EFLAGS: 00010202
  RAX: ffff8801456b0000 RBX: 0000000000000000 RCX: 0000000000000000
  RDX: 00000000000000c0 RSI: 0000000000000000 RDI: 0000000000000000
  RBP: ffff880127777a58 R08: 0000000000015d40 R09: ffff880141c8ecc0
  R10: ffffffffa02a779a R11: 0000000000000004 R12: 0000000000000000
  R13: ffff880141c8ecc0 R14: ffff88013af8d414 R15: ffff880127777a80
  FS:  00007f2c82fb5740(0000) GS:ffff88014f280000(0000) knlGS:0000000000000000
  CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  CR2: 0000000000000000 CR3: 00000001459b2000 CR4: 00000000001407e0
  DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
  DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
  Call Trace:
   [<ffffffff81531b44>] genl_family_rcv_msg+0x1f4/0x2e0
   [<ffffffff81531cc1>] genl_rcv_msg+0x91/0xd0
   [<ffffffff81531339>] netlink_rcv_skb+0xa9/0xc0
   [<ffffffff81531758>] genl_rcv+0x28/0x40
   [<ffffffff81530d62>] netlink_unicast+0x142/0x1f0
   [<ffffffff815310ad>] netlink_sendmsg+0x29d/0x370
   [<ffffffff814f22e9>] sock_sendmsg+0x99/0xd0
   [<ffffffff814f270e>] ___sys_sendmsg+0x39e/0x3b0
   [<ffffffff814f34f2>] __sys_sendmsg+0x42/0x80
   [<ffffffff814f3542>] SyS_sendmsg+0x12/0x20
   [<ffffffff81615e42>] system_call_fastpath+0x16/0x1b
  Code: 60 10 41 0f b6 46 04 0f b6 fb 41 88 45 14 41 0f b6 46 05 41 88
45 15 e8 8c c5 fe ff 84 c0 75 68 49 8b 47 20 4c 8b a0 10 01 00 00 <45>
0f b7 34 24 41 83 ee 04 41 83 fe 03 7e 0e 41 0f b7 44 24 04
  RIP  [<ffffffffa02a77d3>] nl80211_set_reg+0x113/0x2c0 [cfg80211]
   RSP <ffff8801277779f0>
  CR2: 0000000000000000

^ permalink raw reply

* Re: nl80211 NULL pointer dereference
From: David Miller @ 2013-06-19  2:06 UTC (permalink / raw)
  To: torvalds; +Cc: johannes, linville, linux-wireless, netdev
In-Reply-To: <CA+55aFxOde8n0M2=77-TQ2Ea9iz8s-e8zGFwjj6RVyMFXBgxEA@mail.gmail.com>

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: Tue, 18 Jun 2013 15:46:13 -1000

> Hmm. Maybe this is old, but I don't think I've seen it before (who
> knows, maybe it has killed the machine before, I had a hard hang the
> other day).
> 
> It's a NULL pointer dereference in nl80211_set_reg() on my Pixel. The
> machine kind of stayed up afterwards, although with no working
> wireless, and it would not shut down cleanly presumably due to locks
> held etc.
> 
> Any ideas? I'm including the few wireless-related messages that
> happened justr before the oops. Being a pixel, this is with the ath9k
> driver.

nl80211_set_reg() is really careful about validating which netlink
attributes the user has specified, and either not dereferencing or
signalling an error when NULL is seen.

Hmmm...

^ permalink raw reply

* Re: nl80211 NULL pointer dereference
From: Linus Torvalds @ 2013-06-19  2:24 UTC (permalink / raw)
  To: David Miller
  Cc: Johannes Berg, John Linville, Linux Wireless List,
	Network Development
In-Reply-To: <20130618.190632.33329016434510583.davem@davemloft.net>

On Tue, Jun 18, 2013 at 4:06 PM, David Miller <davem@davemloft.net> wrote:
>
> nl80211_set_reg() is really careful about validating which netlink
> attributes the user has specified, and either not dereferencing or
> signalling an error when NULL is seen.
>
> Hmmm...

The code disassembles to

   0: 41 0f b6 46 04       movzbl 0x4(%r14),%eax
   5: 0f b6 fb             movzbl %bl,%edi
   8: 41 88 45 14           mov    %al,0x14(%r13)
   c: 41 0f b6 46 05       movzbl 0x5(%r14),%eax
  11: 41 88 45 15           mov    %al,0x15(%r13)
  15: e8 8c c5 fe ff       callq  0xfffffffffffec5a6
  1a: 84 c0                 test   %al,%al
  1c: 75 68                 jne    0x86
  1e: 49 8b 47 20           mov    0x20(%r15),%rax
  22: 4c 8b a0 10 01 00 00 mov    0x110(%rax),%r12
  29:* 45 0f b7 34 24       movzwl (%r12),%r14d <-- trapping instruction
  2e: 41 83 ee 04           sub    $0x4,%r14d
  32: 41 83 fe 03           cmp    $0x3,%r14d
  36: 7e 0e                 jle    0x46
  38: 41 0f b7 44 24 04     movzwl 0x4(%r12),%eax

(I deleted the two first bytes. they were part of an incomplete
preceding instruction). The "call/test/jne" seems to be this paert:

        /*
         * Disable DFS master mode if the DFS region was
         * not supported or known on this kernel.
         */
        if (reg_supported_dfs_region(dfs_region))
                rd->dfs_region = dfs_region;

and then the two moves into %rax an %r12 seem to be setting up for

        nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],

and then the movzwl (that traps) and the subsequent subtract seems to
be the inlined nla_len(nla), which is the "len" to the
nla_for_each_nested() -> nla_for_each_attr() macro expansion.

So it would seem that it's that

    info->attrs[NL80211_ATTR_REG_RULES]

thing that is NULL.

And yes, the code checks that for being non-NULL in at the top of the
function, but maybe there is a race with something else setting it to
NULL? There is a kzalloc(GFP_KERNEL) in between, so it doesn't even
have to be a very small race...

Hmm? I really don't know this code at all, so I'm just looking at the
source and lining up the oops...

                    Linus

^ permalink raw reply

* Re: [PATCH 6/6] wireless: Add comments about bss refcounting.
From: Julian Calaby @ 2013-06-19  2:51 UTC (permalink / raw)
  To: Ben Greear; +Cc: linux-wireless
In-Reply-To: <1371593017-10985-6-git-send-email-greearb@candelatech.com>

Hi Ben,

On Wed, Jun 19, 2013 at 8:03 AM,  <greearb@candelatech.com> wrote:
> From: Ben Greear <greearb@candelatech.com>
>
> Should help the next person that tries to understand
> the bss refcounting logic.
>
> Signed-off-by: Ben Greear <greearb@candelatech.com>
> ---
>  net/wireless/scan.c |    4 ++++
>  net/wireless/sme.c  |    3 +++
>  2 files changed, 7 insertions(+), 0 deletions(-)
>
> diff --git a/net/wireless/scan.c b/net/wireless/scan.c
> index 542ff6d..834d2f9 100644
> --- a/net/wireless/scan.c
> +++ b/net/wireless/scan.c
> @@ -622,6 +622,7 @@ static int cmp_bss(struct cfg80211_bss *a,
>         }
>  }
>
> +/** Returned bss is reference counted and must be cleaned up appropriately. */

/** is for kernel doc, I'm not sure that is valid kernel doc.

Thanks,

--
Julian Calaby

Email: julian.calaby@gmail.com
Profile: http://www.google.com/profiles/julian.calaby/
.Plan: http://sites.google.com/site/juliancalaby/

^ permalink raw reply

* Re: [PATCH] brcmfmac: Turn off ARP offloading when configured for AP.
From: Arend van Spriel @ 2013-06-19  7:27 UTC (permalink / raw)
  To: Greg KH; +Cc: stable, linux-wireless, Hante Meuleman, John W. Linville
In-Reply-To: <1370508957-12709-1-git-send-email-arend@broadcom.com>

On 06/06/2013 10:55 AM, Arend van Spriel wrote:
> From: Hante Meuleman <meuleman@broadcom.com>

Hi Greg,

I noticed your review announcement for v3.9.7 and did not see the change 
below. I sent it to stable because the original upstream commit did not 
apply. Did I miss some step in the process?

Regards,
Arend

> [backport of upstream commit b3657453f16a7b84eab9b93bb9a9a2901ffc70af]
>
> ARP offloading should only be used in STA or P2P client mode. It
> is currently configured once at init. When being configured for AP
> ARP offloading should be turned off and when AP mode is left it can
> be turned back on.
>
> Reviewed-by: Arend Van Spriel <arend@broadcom.com>
> Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
> Signed-off-by: Arend van Spriel <arend@broadcom.com>
> Signed-off-by: John W. Linville <linville@tuxdriver.com>
> Signed-off-by: Arend van Spriel <arend@broadcom.com>
> ---
>   .../net/wireless/brcm80211/brcmfmac/dhd_common.c   |   18 ---------
>   .../net/wireless/brcm80211/brcmfmac/fwil_types.h   |    6 +++
>   .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c  |   40 +++++++++++++++++++-
>   3 files changed, 45 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
> index 4544342..9480e19 100644
> --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
> +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
> @@ -26,7 +26,6 @@
>   #include "fwil.h"
>
>   #define PKTFILTER_BUF_SIZE		128
> -#define BRCMF_ARPOL_MODE		0xb	/* agent|snoop|peer_autoreply */
>   #define BRCMF_DEFAULT_BCN_TIMEOUT	3
>   #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME	40
>   #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME	40
> @@ -337,23 +336,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
>   		goto done;
>   	}
>
> -	/* Try to set and enable ARP offload feature, this may fail */
> -	err = brcmf_fil_iovar_int_set(ifp, "arp_ol", BRCMF_ARPOL_MODE);
> -	if (err) {
> -		brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
> -			  BRCMF_ARPOL_MODE, err);
> -		err = 0;
> -	} else {
> -		err = brcmf_fil_iovar_int_set(ifp, "arpoe", 1);
> -		if (err) {
> -			brcmf_dbg(TRACE, "failed to enable ARP offload err = %d\n",
> -				  err);
> -			err = 0;
> -		} else
> -			brcmf_dbg(TRACE, "successfully enabled ARP offload to 0x%x\n",
> -				  BRCMF_ARPOL_MODE);
> -	}
> -
>   	/* Setup packet filter */
>   	brcmf_c_pktfilter_offload_set(ifp, BRCMF_DEFAULT_PACKET_FILTER);
>   	brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER,
> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
> index 0f2c83b..665ef69 100644
> --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
> +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
> @@ -23,6 +23,12 @@
>
>   #define BRCMF_FIL_ACTION_FRAME_SIZE	1800
>
> +/* ARP Offload feature flags for arp_ol iovar */
> +#define BRCMF_ARP_OL_AGENT		0x00000001
> +#define BRCMF_ARP_OL_SNOOP		0x00000002
> +#define BRCMF_ARP_OL_HOST_AUTO_REPLY	0x00000004
> +#define BRCMF_ARP_OL_PEER_AUTO_REPLY	0x00000008
> +
>
>   enum brcmf_fil_p2p_if_types {
>   	BRCMF_FIL_P2P_IF_CLIENT,
> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
> index 78da3ef..d5c4e24 100644
> --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
> +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
> @@ -505,6 +505,38 @@ send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
>   	return err;
>   }
>
> +static s32
> +brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
> +{
> +	s32 err;
> +	u32 mode;
> +
> +	if (enable)
> +		mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
> +	else
> +		mode = 0;
> +
> +	/* Try to set and enable ARP offload feature, this may fail, then it  */
> +	/* is simply not supported and err 0 will be returned                 */
> +	err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
> +	if (err) {
> +		brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
> +			  mode, err);
> +		err = 0;
> +	} else {
> +		err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
> +		if (err) {
> +			brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
> +				  enable, err);
> +			err = 0;
> +		} else
> +			brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
> +				  enable, mode);
> +	}
> +
> +	return err;
> +}
> +
>   static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
>   						     const char *name,
>   						     enum nl80211_iftype type,
> @@ -3709,6 +3741,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
>   	}
>
>   	brcmf_set_mpc(ndev, 0);
> +	brcmf_configure_arp_offload(ifp, false);
>
>   	/* find the RSN_IE */
>   	rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
> @@ -3815,8 +3848,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
>   	set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
>
>   exit:
> -	if (err)
> +	if (err) {
>   		brcmf_set_mpc(ndev, 1);
> +		brcmf_configure_arp_offload(ifp, true);
> +	}
>   	return err;
>   }
>
> @@ -3857,6 +3892,7 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
>   			brcmf_err("bss_enable config failed %d\n", err);
>   	}
>   	brcmf_set_mpc(ndev, 1);
> +	brcmf_configure_arp_offload(ifp, true);
>   	set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
>   	clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
>
> @@ -4995,6 +5031,8 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
>   	if (err)
>   		goto default_conf_out;
>
> +	brcmf_configure_arp_offload(ifp, true);
> +
>   	cfg->dongle_up = true;
>   default_conf_out:
>
>



^ permalink raw reply

* Re: nl80211 NULL pointer dereference
From: David Miller @ 2013-06-19  7:47 UTC (permalink / raw)
  To: torvalds; +Cc: johannes, linville, linux-wireless, netdev
In-Reply-To: <CA+55aFz=eG5-zh1toHxrx=4Qm4DvwyiBCU3u-6tc0-utfZ6xiA@mail.gmail.com>

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: Tue, 18 Jun 2013 16:24:57 -1000

> And yes, the code checks that for being non-NULL in at the top of the
> function, but maybe there is a race with something else setting it to
> NULL? There is a kzalloc(GFP_KERNEL) in between, so it doesn't even
> have to be a very small race...

The nl80211 code uses a flag for each netlink command to determine
whether the RTNL mutex should be held across the operation.

This is handled in the pre_doit and post_doit methods implemented
in nl80211.c.

And this operation, in fact, just so happens to be one that doesn't
have the "take the RTNL mutex" flag set.

But for internal consistency of the netlink message itself, the RTNL
mutex should not matter.  It's in a private SKB buffer which is in use
only by the ->doit() method.


^ permalink raw reply


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