Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH] mac80211: fix TX aggregation TID struct leak
From: Ben Greear @ 2013-06-12 22:13 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Johannes Berg
In-Reply-To: <1371070209-24107-1-git-send-email-johannes@sipsolutions.net>

On 06/12/2013 01:50 PM, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
>
> Ben reports that kmemleak is saying TX aggregation TID
> structs are leaked. Given his workload, I suspect that
> they're leaked because stations are destroyed before
> their aggregation sessions get a chance to start. Fix
> this by simply freeing structs that are not used yet.
>
> Reported-by: Ben Greear <greearb@candelatech.com>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
> ---
>   net/mac80211/sta_info.c | 1 +
>   1 file changed, 1 insertion(+)
>
> diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
> index b429798..aaf68d2 100644
> --- a/net/mac80211/sta_info.c
> +++ b/net/mac80211/sta_info.c
> @@ -149,6 +149,7 @@ static void cleanup_single_sta(struct sta_info *sta)
>   	 * directly by station destruction.
>   	 */
>   	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
> +		kfree(sta->ampdu_mlme.tid_start_tx[i]);
>   		tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
>   		if (!tid_tx)
>   			continue;
>


This does fix the TID leakage for me.

Tested-by:  Ben Greear <greearb@candelatech.com>

Thanks,
Ben

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


^ permalink raw reply

* Re: pull request: wireless-next 2013-06-11
From: David Miller @ 2013-06-12 22:01 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, netdev
In-Reply-To: <20130611190546.GE3196@tuxdriver.com>

From: "John W. Linville" <linville@tuxdriver.com>
Date: Tue, 11 Jun 2013 15:05:48 -0400

> This pull request is intended for the 3.11 stream...
> 
> One big highlight is the cw1200 driver the ST-E CW1100 & CW1200
> WLAN chipsets.  This one has been lingering for a while, lacking
> some review comments.  Once started getting pulled into linux-next,
> it got a bit more attention and a number of improvements were made
> over the initial cut.  No doubt there will be more changes ahead,
> but I think it is looking alright at this point.
> 
> Along with that, there is the usual flurry of updates to the mac80211
> core and the iwlwifi, mwifiex, ath9k, rt2x00, wil6210, and other
> drivers.  A few of the highlights are some rt2x00 refactoring/cleanup
> by Gabor Juhos, some rt2800 hardware support enhancements by Stanislaw
> Gruszka, some iwlwifi power management updates from Alexander Bondar,
> some enhanced bcma SPROM support from Rafał Miłecki, and a variety
> of other things here and there.

Pulled, thanks John.

^ permalink raw reply

* Re: pull-request: mac80211 2013-06-12
From: John W. Linville @ 2013-06-12 21:56 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1371021295.8601.8.camel@jlt4.sipsolutions.net>

On Wed, Jun 12, 2013 at 09:14:55AM +0200, Johannes Berg wrote:
> Let's try that again :-)
> 
> Following davem's complaint about my patch, here's a new pull request
> w/o the patch he was complaining about, but instead with the const fix
> rolled into the fix.
> 
> I have a fix for radar detection, one for rate control and a workaround
> for broken HT APs which is a regression fix because we didn't rely on
> them to be correct before.
> 
> johannes
> 
> 
> The following changes since commit ac20976dcaeea3e77e40e9aac8f3799d2a22ea2b:
> 
>   mac80211: Allow single vif mac address change with addr_mask (2013-05-27 11:26:48 +0200)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git for-john
> 
> for you to fetch changes up to 795d855d56c6d172f50a974f603ba923ac93ee76:
> 
>   mac80211: Fix rate control mask matching call (2013-06-12 09:12:43 +0200)

Pulling now...

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

^ permalink raw reply

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

On Wed, Jun 12, 2013 at 02:17:29PM +0200, Johannes Berg wrote:
> Amending this ...
> 
> 
> I picked up Nikolay's patch for the chain noise calibration bug that
> seems to have been there forever, a fix from Emmanuel for setting TX
> flags on BAR frames and a fix of my own to avoid printing
> request_module() errors if the kernel isn't even modular. We also have
> our own version of Stanislaw's fix for rate control.
> 
> johannes
> 
> The following changes since commit a87783699b23395c46bbeeb5d28f6db24897bf26:
> 
>   iwlwifi: dvm: fix zero LQ CMD sending avoidance (2013-05-27 11:33:57 +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 622ebe994f6866b8d46ee5d3bcc329ed65d3722d:
> 
>   iwlwifi: fix rate control regression (2013-06-12 14:13:39 +0200)

Pulling now...

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

^ permalink raw reply

* Re: Regression in 9390ace brcmfmac: free net device when registration fails
From: Stephen Warren @ 2013-06-12 21:19 UTC (permalink / raw)
  To: Arend van Spriel
  Cc: John W. Linville, Hante Meuleman,
	'linux-wireless@vger.kernel.org',
	linux-next@vger.kernel.org
In-Reply-To: <51B100C2.8070905@wwwdotorg.org>

On 06/06/2013 03:36 PM, Stephen Warren wrote:
> On 06/06/2013 03:10 PM, Arend van Spriel wrote:
>> On 06/04/13 14:58, Arend van Spriel wrote:
>>> On 06/04/2013 12:56 AM, Stephen Warren wrote:
>>>> (John, note that this commit is part of the pull request you sent to
>>>> Dave today)
>>>>
>>>> Arend,
>>>>
>>>> Commit 9390ace "brcmfmac: free net device when registration fails"
>>>> causes a regression.
>>>>
>>>> I had the BCM4330 firmware present in my root fs, whereas my HW is a
>>>> BCM4329. With this patch applied, I get a kernel panic on boot. With it
>>>> reverted, I see that no issues of that nature. This is true in
>>>> next-20130531 (and also 5/30 and 6/1 but not earlier). A bisect of
>>>> Linus's tree followed by a merge of John's wireless pull request from
>>>> today pointed at this same commit.
>>>
>>> Thanks, Stephen
>>>
>>> I will look into this.
>>
>> Hi Stephen,
>>
>> Can you try the attached patch? If it does not solve the issue, could
>> you provide a log.
> 
> Yes, that works great, thanks.
> 
> Tested-by: Stephen Warren <swarren@nvidia.com>

Did this patch get applied anywhere? I was hoping it'd go into 3.10-rc*
given it's a user-triggerable backtrace introduced in 3.10-rc*.

^ permalink raw reply

* [PATCH] mac80211: Ensure tid_start_tx is protected by sta->lock.
From: greearb @ 2013-06-12 21:08 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear

From: Ben Greear <greearb@candelatech.com>

All accesses of the tid_start_tx lock should be protected
by sta->lock if there is any chance that another thread
could still be accessing the sta object.

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

diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 0db25d4..87b8b23 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -283,13 +283,14 @@ void ieee80211_ba_session_work(struct work_struct *work)
 				sta, tid, WLAN_BACK_RECIPIENT,
 				WLAN_REASON_UNSPECIFIED, true);
 
+		spin_lock_bh(&sta->lock);
+
 		tid_tx = sta->ampdu_mlme.tid_start_tx[tid];
 		if (tid_tx) {
 			/*
 			 * Assign it over to the normal tid_tx array
 			 * where it "goes live".
 			 */
-			spin_lock_bh(&sta->lock);
 
 			sta->ampdu_mlme.tid_start_tx[tid] = NULL;
 			/* could there be a race? */
@@ -302,6 +303,7 @@ void ieee80211_ba_session_work(struct work_struct *work)
 			ieee80211_tx_ba_session_handle_start(sta, tid);
 			continue;
 		}
+		spin_unlock_bh(&sta->lock);
 
 		tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 		if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP,
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index c509423..de40c5b 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -204,6 +204,7 @@ struct tid_ampdu_rx {
  *	driver requested to close until the work for it runs
  * @mtx: mutex to protect all TX data (except non-NULL assignments
  *	to tid_tx[idx], which are protected by the sta spinlock)
+ *	tid_start_tx is also protected by sta->lock.
  */
 struct sta_ampdu_mlme {
 	struct mutex mtx;
-- 
1.7.3.4


^ permalink raw reply related

* Re: kmemleak report related to ieee80211_start_tx_ba_session, tid_start_tx locking issues?
From: Johannes Berg @ 2013-06-12 21:01 UTC (permalink / raw)
  To: Ben Greear; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <51B8E101.2050503@candelatech.com>

On Wed, 2013-06-12 at 13:58 -0700, Ben Greear wrote:

> > When did this report get printed?
> 
> I have a system with 100 or so stations constantly trying to
> associate with a set of APs that can handle < 100.  This
> effectively causes constant churn of re-associations and
> associated logic...

Right ... I figured it was this.

> Good for shaking out bugs it seems :)
> 
> These and other leaks show up after a few minutes of
> running this test scenario.  It's not a huge number of
> leaks, however...so usually stations go away w/out leaking.

That's not all too surprising really, the work should run quickly I
guess.

Anyway I guess kmemleak doesn't actually let you pinpoint when the leak
occurred because it just scans periodically and not on every kfree, so
n/m my question.


> >   	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
> > +		kfree(sta->ampdu_mlme.tid_start_tx[i]);
> >   		tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
> >   		if (!tid_tx)
> >   			continue;
> 
> Looks reasonable to me.  I was about to start testing similar logic
> in sta_info_free(), but likely your patch is more proper.
> 
> I'll give it a try now.

Thanks.

johannes


^ permalink raw reply

* Re: kmemleak report related to ieee80211_start_tx_ba_session, tid_start_tx locking issues?
From: Ben Greear @ 2013-06-12 20:58 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <1371069960.8601.35.camel@jlt4.sipsolutions.net>

On 06/12/2013 01:46 PM, Johannes Berg wrote:
> On Wed, 2013-06-12 at 11:21 -0700, Ben Greear wrote:
>
>> In ieee80211_start_tx_ba_session we are accessing and assigning the tid_start_tx
>> without holding the ampdu_mlme.mtx mutex.
>>
>> 	spin_lock_bh(&sta->lock);
>> .....
>> 	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
>> 	/* check if the TID is not in aggregation flow already */
>> 	if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
>>
>> ....
>>
>> 	/*
>> 	 * Finally, assign it to the start array; the work item will
>> 	 * collect it and move it to the normal array.
>> 	 */
>> 	sta->ampdu_mlme.tid_start_tx[tid] = tid_tx;
>>
>>
>> Elsewhere, in ieee80211_ba_session_work, we access the tid_start_tx
>> without the sta->lock held, but with the ampdu_mlme.mtx held.
>
> Yeah, that seems wrong.
>
>> I think we should probably hold ampdu_mlme.mtx in ieee80211_start_tx_ba_session
>> or make sure we hold sta->lock in ieee80211_ba_session_work.
>
> Can't hold the mutex there, but we can do the lock (I'll comment on your
> patch separately)
>
>> unreferenced object 0xffff880219b4de40 (size 192):
>>     comm "softirq", pid 0, jiffies 4296416789 (age 1257.971s)
>>     hex dump (first 32 bytes):
>>       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
>>       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
>>     backtrace:
>>       [<ffffffff815bc02c>] kmemleak_alloc+0x73/0x98
>>       [<ffffffff8117d4b4>] slab_post_alloc_hook+0x28/0x2a
>>       [<ffffffff8117f4a6>] kmem_cache_alloc_trace+0xa5/0xcc
>>       [<ffffffffa0365221>] ieee80211_start_tx_ba_session+0x24b/0x360 [mac80211]
>>       [<ffffffffa03a98f3>] minstrel_ht_tx_status+0x79a/0x7a9 [mac80211]
>>       [<ffffffffa035d1cd>] ieee80211_tx_status+0x3af/0x947 [mac80211]
>
> When did this report get printed?

I have a system with 100 or so stations constantly trying to
associate with a set of APs that can handle < 100.  This
effectively causes constant churn of re-associations and
associated logic...

Good for shaking out bugs it seems :)

These and other leaks show up after a few minutes of
running this test scenario.  It's not a huge number of
leaks, however...so usually stations go away w/out leaking.

> I have a feeling what happens is that start is requested, and then
> before ieee80211_ba_session_work() gets a chance to run the station is
> destroyed.
>
> Should probably have something like this:
>
> diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
> index b429798..aaf68d2 100644
> --- a/net/mac80211/sta_info.c
> +++ b/net/mac80211/sta_info.c
> @@ -149,6 +149,7 @@ static void cleanup_single_sta(struct sta_info *sta)
>   	 * directly by station destruction.
>   	 */
>   	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
> +		kfree(sta->ampdu_mlme.tid_start_tx[i]);
>   		tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
>   		if (!tid_tx)
>   			continue;

Looks reasonable to me.  I was about to start testing similar logic
in sta_info_free(), but likely your patch is more proper.

I'll give it a try now.

Thanks,
Ben

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


^ permalink raw reply

* [PATCH] mac80211: fix TX aggregation TID struct leak
From: Johannes Berg @ 2013-06-12 20:50 UTC (permalink / raw)
  To: linux-wireless; +Cc: greearb, Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

Ben reports that kmemleak is saying TX aggregation TID
structs are leaked. Given his workload, I suspect that
they're leaked because stations are destroyed before
their aggregation sessions get a chance to start. Fix
this by simply freeing structs that are not used yet.

Reported-by: Ben Greear <greearb@candelatech.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/sta_info.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index b429798..aaf68d2 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -149,6 +149,7 @@ static void cleanup_single_sta(struct sta_info *sta)
 	 * directly by station destruction.
 	 */
 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+		kfree(sta->ampdu_mlme.tid_start_tx[i]);
 		tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
 		if (!tid_tx)
 			continue;
-- 
1.8.0


^ permalink raw reply related

* Re: [RFC] mac80211:  Ensure tid_start_tx is protected by sta->lock.
From: Johannes Berg @ 2013-06-12 20:47 UTC (permalink / raw)
  To: greearb; +Cc: linux-wireless
In-Reply-To: <1371068409-10407-1-git-send-email-greearb@candelatech.com>

On Wed, 2013-06-12 at 13:20 -0700, greearb@candelatech.com wrote:

> I believe this is more correct, though it did not fix the
> memory leak I was chasing when I found this code.

That description could use some work :-)

> +		spin_lock_bh(&sta->lock);
> +
>  		tid_tx = sta->ampdu_mlme.tid_start_tx[tid];
>  		if (tid_tx) {
>  			/*
>  			 * Assign it over to the normal tid_tx array
>  			 * where it "goes live".
>  			 */
> -			spin_lock_bh(&sta->lock);
>  
>  			sta->ampdu_mlme.tid_start_tx[tid] = NULL;
>  			/* could there be a race? */
> @@ -301,6 +302,8 @@ void ieee80211_ba_session_work(struct work_struct *work)
>  
>  			ieee80211_tx_ba_session_handle_start(sta, tid);
>  			continue;
> +		} else {
> +			spin_unlock_bh(&sta->lock);
>  		}
>  

You could just put the unlock after the if block, given the continue in
it, I think I'd prefer that.

>  		tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
> diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
> index c509423..0f85418 100644
> --- a/net/mac80211/sta_info.h
> +++ b/net/mac80211/sta_info.h
> @@ -204,6 +204,7 @@ struct tid_ampdu_rx {
>   *	driver requested to close until the work for it runs
>   * @mtx: mutex to protect all TX data (except non-NULL assignments
>   *	to tid_tx[idx], which are protected by the sta spinlock)
> + *      tid_start_tx is also protected by sta->lock.

That should be a tab.

johannes


^ permalink raw reply

* Re: kmemleak report related to ieee80211_start_tx_ba_session, tid_start_tx locking issues?
From: Johannes Berg @ 2013-06-12 20:46 UTC (permalink / raw)
  To: Ben Greear; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <51B8BC3E.40905@candelatech.com>

On Wed, 2013-06-12 at 11:21 -0700, Ben Greear wrote:

> In ieee80211_start_tx_ba_session we are accessing and assigning the tid_start_tx
> without holding the ampdu_mlme.mtx mutex.
> 
> 	spin_lock_bh(&sta->lock);
> .....
> 	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
> 	/* check if the TID is not in aggregation flow already */
> 	if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
> 
> ....
> 
> 	/*
> 	 * Finally, assign it to the start array; the work item will
> 	 * collect it and move it to the normal array.
> 	 */
> 	sta->ampdu_mlme.tid_start_tx[tid] = tid_tx;
> 
> 
> Elsewhere, in ieee80211_ba_session_work, we access the tid_start_tx
> without the sta->lock held, but with the ampdu_mlme.mtx held.

Yeah, that seems wrong.

> I think we should probably hold ampdu_mlme.mtx in ieee80211_start_tx_ba_session
> or make sure we hold sta->lock in ieee80211_ba_session_work.

Can't hold the mutex there, but we can do the lock (I'll comment on your
patch separately)

> unreferenced object 0xffff880219b4de40 (size 192):
>    comm "softirq", pid 0, jiffies 4296416789 (age 1257.971s)
>    hex dump (first 32 bytes):
>      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
>      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
>    backtrace:
>      [<ffffffff815bc02c>] kmemleak_alloc+0x73/0x98
>      [<ffffffff8117d4b4>] slab_post_alloc_hook+0x28/0x2a
>      [<ffffffff8117f4a6>] kmem_cache_alloc_trace+0xa5/0xcc
>      [<ffffffffa0365221>] ieee80211_start_tx_ba_session+0x24b/0x360 [mac80211]
>      [<ffffffffa03a98f3>] minstrel_ht_tx_status+0x79a/0x7a9 [mac80211]
>      [<ffffffffa035d1cd>] ieee80211_tx_status+0x3af/0x947 [mac80211]

When did this report get printed?

I have a feeling what happens is that start is requested, and then
before ieee80211_ba_session_work() gets a chance to run the station is
destroyed.

Should probably have something like this:

diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index b429798..aaf68d2 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -149,6 +149,7 @@ static void cleanup_single_sta(struct sta_info *sta)
 	 * directly by station destruction.
 	 */
 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+		kfree(sta->ampdu_mlme.tid_start_tx[i]);
 		tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
 		if (!tid_tx)
 			continue;

johannes


^ permalink raw reply related

* Re: pull request: wireless 2013-06-12
From: David Miller @ 2013-06-12 20:36 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <20130612150926.GC11589@tuxdriver.com>

From: "John W. Linville" <linville@tuxdriver.com>
Date: Wed, 12 Jun 2013 11:09:26 -0400

> For now I have dropped the mac80211 tree from this request.
> We are developing a little backlog of fixes and I would like to
> avoid introducing any more uncertainty to this pull request for the
> 3.10 stream.  All the other bits are the same as what was in the
> 2013-06-06 request, including the ath9k fixes intended to address
> the problems observed by Linus w/ his Pixel, and a CVE fix for a
> potential security issue in the b43 driver.

Pulled, thanks John.

^ permalink raw reply

* [RFC] mac80211:  Ensure tid_start_tx is protected by sta->lock.
From: greearb @ 2013-06-12 20:20 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear

From: Ben Greear <greearb@candelatech.com>

I believe this is more correct, though it did not fix the
memory leak I was chasing when I found this code.

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

diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 0db25d4..c6256b4 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -283,13 +283,14 @@ void ieee80211_ba_session_work(struct work_struct *work)
 				sta, tid, WLAN_BACK_RECIPIENT,
 				WLAN_REASON_UNSPECIFIED, true);
 
+		spin_lock_bh(&sta->lock);
+
 		tid_tx = sta->ampdu_mlme.tid_start_tx[tid];
 		if (tid_tx) {
 			/*
 			 * Assign it over to the normal tid_tx array
 			 * where it "goes live".
 			 */
-			spin_lock_bh(&sta->lock);
 
 			sta->ampdu_mlme.tid_start_tx[tid] = NULL;
 			/* could there be a race? */
@@ -301,6 +302,8 @@ void ieee80211_ba_session_work(struct work_struct *work)
 
 			ieee80211_tx_ba_session_handle_start(sta, tid);
 			continue;
+		} else {
+			spin_unlock_bh(&sta->lock);
 		}
 
 		tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index c509423..0f85418 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -204,6 +204,7 @@ struct tid_ampdu_rx {
  *	driver requested to close until the work for it runs
  * @mtx: mutex to protect all TX data (except non-NULL assignments
  *	to tid_tx[idx], which are protected by the sta spinlock)
+ *      tid_start_tx is also protected by sta->lock.
  */
 struct sta_ampdu_mlme {
 	struct mutex mtx;
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH RESEND] carl9170: add support for the new rate control API
From: Christian Lamparter @ 2013-06-12 19:35 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville

With the new rate control API, the driver can now apply the
tx rate to outgoing frames just before they are uploaded to
the device. This is important because the rate control can
now react to fading or improving links a bit sooner.

Also, the driver no longer needs to sort the outgoing frames
for sample attempts (which affected the size of A-MPDUs and
the throughput of the link). For aggregated data frames, the
driver (and rate control) needs only to calculate and apply
a single set of tx rates to every subframe of the whole
aggregate.

Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>

---
rfc -> v1:
	- add pointers to sta and vif in the private tid struct.
	  (saves lookup)
	- acquire tx rate set and apply it to all sub frames
	  during ampdu frame selection
	  (saves an extra loop)
---
 drivers/net/wireless/ath/carl9170/carl9170.h |    3 +
 drivers/net/wireless/ath/carl9170/main.c     |    3 +
 drivers/net/wireless/ath/carl9170/tx.c       |  182 +++++++++++++++-----------
 3 files changed, 110 insertions(+), 78 deletions(-)

diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index 9dce106..8596aba 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -133,6 +133,9 @@ struct carl9170_sta_tid {
 
 	/* Preaggregation reorder queue */
 	struct sk_buff_head queue;
+
+	struct ieee80211_sta *sta;
+	struct ieee80211_vif *vif;
 };
 
 #define CARL9170_QUEUE_TIMEOUT		256
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index e9010a4..4a33c6e 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1448,6 +1448,8 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
 		tid_info->state = CARL9170_TID_STATE_PROGRESS;
 		tid_info->tid = tid;
 		tid_info->max = sta_info->ampdu_max_len;
+		tid_info->sta = sta;
+		tid_info->vif = vif;
 
 		INIT_LIST_HEAD(&tid_info->list);
 		INIT_LIST_HEAD(&tid_info->tmp_list);
@@ -1857,6 +1859,7 @@ void *carl9170_alloc(size_t priv_size)
 		     IEEE80211_HW_SUPPORTS_PS |
 		     IEEE80211_HW_PS_NULLFUNC_STACK |
 		     IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
+		     IEEE80211_HW_SUPPORTS_RC_TABLE |
 		     IEEE80211_HW_SIGNAL_DBM;
 
 	if (!modparam_noht) {
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
index c61cafa..e3f696e 100644
--- a/drivers/net/wireless/ath/carl9170/tx.c
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -625,7 +625,7 @@ static void carl9170_tx_ampdu_timeout(struct ar9170 *ar)
 		    msecs_to_jiffies(CARL9170_QUEUE_TIMEOUT)))
 			goto unlock;
 
-		sta = __carl9170_get_tx_sta(ar, skb);
+		sta = iter->sta;
 		if (WARN_ON(!sta))
 			goto unlock;
 
@@ -866,6 +866,93 @@ static bool carl9170_tx_cts_check(struct ar9170 *ar,
 	return false;
 }
 
+static void carl9170_tx_get_rates(struct ar9170 *ar,
+				  struct ieee80211_vif *vif,
+				  struct ieee80211_sta *sta,
+				  struct sk_buff *skb)
+{
+	struct ieee80211_tx_info *info;
+
+	BUILD_BUG_ON(IEEE80211_TX_MAX_RATES < CARL9170_TX_MAX_RATES);
+	BUILD_BUG_ON(IEEE80211_TX_MAX_RATES > IEEE80211_TX_RATE_TABLE_SIZE);
+
+	info = IEEE80211_SKB_CB(skb);
+
+	ieee80211_get_tx_rates(vif, sta, skb,
+			       info->control.rates,
+			       IEEE80211_TX_MAX_RATES);
+}
+
+static void carl9170_tx_apply_rateset(struct ar9170 *ar,
+				      struct ieee80211_tx_info *sinfo,
+				      struct sk_buff *skb)
+{
+	struct ieee80211_tx_rate *txrate;
+	struct ieee80211_tx_info *info;
+	struct _carl9170_tx_superframe *txc = (void *) skb->data;
+	int i;
+	bool ampdu;
+	bool no_ack;
+
+	info = IEEE80211_SKB_CB(skb);
+	ampdu = !!(info->flags & IEEE80211_TX_CTL_AMPDU);
+	no_ack = !!(info->flags & IEEE80211_TX_CTL_NO_ACK);
+
+	/* Set the rate control probe flag for all (sub-) frames.
+	 * This is because the TX_STATS_AMPDU flag is only set on
+	 * the last frame, so it has to be inherited.
+	 */
+	info->flags |= (sinfo->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
+
+	/* NOTE: For the first rate, the ERP & AMPDU flags are directly
+	 * taken from mac_control. For all fallback rate, the firmware
+	 * updates the mac_control flags from the rate info field.
+	 */
+	for (i = 0; i < CARL9170_TX_MAX_RATES; i++) {
+		__le32 phy_set;
+
+		txrate = &sinfo->control.rates[i];
+		if (txrate->idx < 0)
+			break;
+
+		phy_set = carl9170_tx_physet(ar, info, txrate);
+		if (i == 0) {
+			__le16 mac_tmp = cpu_to_le16(0);
+
+			/* first rate - part of the hw's frame header */
+			txc->f.phy_control = phy_set;
+
+			if (ampdu && txrate->flags & IEEE80211_TX_RC_MCS)
+				mac_tmp |= cpu_to_le16(AR9170_TX_MAC_AGGR);
+
+			if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack))
+				mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS);
+			else if (carl9170_tx_cts_check(ar, txrate))
+				mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS);
+
+			txc->f.mac_control |= mac_tmp;
+		} else {
+			/* fallback rates are stored in the firmware's
+			 * retry rate set array.
+			 */
+			txc->s.rr[i - 1] = phy_set;
+		}
+
+		SET_VAL(CARL9170_TX_SUPER_RI_TRIES, txc->s.ri[i],
+			txrate->count);
+
+		if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack))
+			txc->s.ri[i] |= (AR9170_TX_MAC_PROT_RTS <<
+				CARL9170_TX_SUPER_RI_ERP_PROT_S);
+		else if (carl9170_tx_cts_check(ar, txrate))
+			txc->s.ri[i] |= (AR9170_TX_MAC_PROT_CTS <<
+				CARL9170_TX_SUPER_RI_ERP_PROT_S);
+
+		if (ampdu && (txrate->flags & IEEE80211_TX_RC_MCS))
+			txc->s.ri[i] |= CARL9170_TX_SUPER_RI_AMPDU;
+	}
+}
+
 static int carl9170_tx_prepare(struct ar9170 *ar,
 			       struct ieee80211_sta *sta,
 			       struct sk_buff *skb)
@@ -874,13 +961,10 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
 	struct _carl9170_tx_superframe *txc;
 	struct carl9170_vif_info *cvif;
 	struct ieee80211_tx_info *info;
-	struct ieee80211_tx_rate *txrate;
 	struct carl9170_tx_info *arinfo;
 	unsigned int hw_queue;
-	int i;
 	__le16 mac_tmp;
 	u16 len;
-	bool ampdu, no_ack;
 
 	BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data));
 	BUILD_BUG_ON(sizeof(struct _carl9170_tx_superdesc) !=
@@ -889,8 +973,6 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
 	BUILD_BUG_ON(sizeof(struct _ar9170_tx_hwdesc) !=
 		     AR9170_TX_HWDESC_LEN);
 
-	BUILD_BUG_ON(IEEE80211_TX_MAX_RATES < CARL9170_TX_MAX_RATES);
-
 	BUILD_BUG_ON(AR9170_MAX_VIRTUAL_MAC >
 		((CARL9170_TX_SUPER_MISC_VIF_ID >>
 		 CARL9170_TX_SUPER_MISC_VIF_ID_S) + 1));
@@ -932,8 +1014,7 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
 	mac_tmp |= cpu_to_le16((hw_queue << AR9170_TX_MAC_QOS_S) &
 			       AR9170_TX_MAC_QOS);
 
-	no_ack = !!(info->flags & IEEE80211_TX_CTL_NO_ACK);
-	if (unlikely(no_ack))
+	if (unlikely(info->flags & IEEE80211_TX_CTL_NO_ACK))
 		mac_tmp |= cpu_to_le16(AR9170_TX_MAC_NO_ACK);
 
 	if (info->control.hw_key) {
@@ -954,8 +1035,7 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
 		}
 	}
 
-	ampdu = !!(info->flags & IEEE80211_TX_CTL_AMPDU);
-	if (ampdu) {
+	if (info->flags & IEEE80211_TX_CTL_AMPDU) {
 		unsigned int density, factor;
 
 		if (unlikely(!sta || !cvif))
@@ -982,50 +1062,6 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
 			txc->s.ampdu_settings, factor);
 	}
 
-	/*
-	 * NOTE: For the first rate, the ERP & AMPDU flags are directly
-	 * taken from mac_control. For all fallback rate, the firmware
-	 * updates the mac_control flags from the rate info field.
-	 */
-	for (i = 0; i < CARL9170_TX_MAX_RATES; i++) {
-		__le32 phy_set;
-		txrate = &info->control.rates[i];
-		if (txrate->idx < 0)
-			break;
-
-		phy_set = carl9170_tx_physet(ar, info, txrate);
-		if (i == 0) {
-			/* first rate - part of the hw's frame header */
-			txc->f.phy_control = phy_set;
-
-			if (ampdu && txrate->flags & IEEE80211_TX_RC_MCS)
-				mac_tmp |= cpu_to_le16(AR9170_TX_MAC_AGGR);
-			if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack))
-				mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS);
-			else if (carl9170_tx_cts_check(ar, txrate))
-				mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS);
-
-		} else {
-			/* fallback rates are stored in the firmware's
-			 * retry rate set array.
-			 */
-			txc->s.rr[i - 1] = phy_set;
-		}
-
-		SET_VAL(CARL9170_TX_SUPER_RI_TRIES, txc->s.ri[i],
-			txrate->count);
-
-		if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack))
-			txc->s.ri[i] |= (AR9170_TX_MAC_PROT_RTS <<
-				CARL9170_TX_SUPER_RI_ERP_PROT_S);
-		else if (carl9170_tx_cts_check(ar, txrate))
-			txc->s.ri[i] |= (AR9170_TX_MAC_PROT_CTS <<
-				CARL9170_TX_SUPER_RI_ERP_PROT_S);
-
-		if (ampdu && (txrate->flags & IEEE80211_TX_RC_MCS))
-			txc->s.ri[i] |= CARL9170_TX_SUPER_RI_AMPDU;
-	}
-
 	txc->s.len = cpu_to_le16(skb->len);
 	txc->f.length = cpu_to_le16(len + FCS_LEN);
 	txc->f.mac_control = mac_tmp;
@@ -1086,31 +1122,12 @@ static void carl9170_set_ampdu_params(struct ar9170 *ar, struct sk_buff *skb)
 	}
 }
 
-static bool carl9170_tx_rate_check(struct ar9170 *ar, struct sk_buff *_dest,
-				   struct sk_buff *_src)
-{
-	struct _carl9170_tx_superframe *dest, *src;
-
-	dest = (void *) _dest->data;
-	src = (void *) _src->data;
-
-	/*
-	 * The mac80211 rate control algorithm expects that all MPDUs in
-	 * an AMPDU share the same tx vectors.
-	 * This is not really obvious right now, because the hardware
-	 * does the AMPDU setup according to its own rulebook.
-	 * Our nicely assembled, strictly monotonic increasing mpdu
-	 * chains will be broken up, mashed back together...
-	 */
-
-	return (dest->f.phy_control == src->f.phy_control);
-}
-
 static void carl9170_tx_ampdu(struct ar9170 *ar)
 {
 	struct sk_buff_head agg;
 	struct carl9170_sta_tid *tid_info;
 	struct sk_buff *skb, *first;
+	struct ieee80211_tx_info *tx_info_first;
 	unsigned int i = 0, done_ampdus = 0;
 	u16 seq, queue, tmpssn;
 
@@ -1156,6 +1173,7 @@ retry:
 			goto processed;
 		}
 
+		tx_info_first = NULL;
 		while ((skb = skb_peek(&tid_info->queue))) {
 			/* strict 0, 1, ..., n - 1, n frame sequence order */
 			if (unlikely(carl9170_get_seq(skb) != seq))
@@ -1166,8 +1184,13 @@ retry:
 			    (tid_info->max - 1)))
 				break;
 
-			if (!carl9170_tx_rate_check(ar, skb, first))
-				break;
+			if (!tx_info_first) {
+				carl9170_tx_get_rates(ar, tid_info->vif,
+						      tid_info->sta, first);
+				tx_info_first = IEEE80211_SKB_CB(first);
+			}
+
+			carl9170_tx_apply_rateset(ar, tx_info_first, skb);
 
 			atomic_inc(&ar->tx_ampdu_upload);
 			tid_info->snx = seq = SEQ_NEXT(seq);
@@ -1182,8 +1205,7 @@ retry:
 		if (skb_queue_empty(&tid_info->queue) ||
 		    carl9170_get_seq(skb_peek(&tid_info->queue)) !=
 		    tid_info->snx) {
-			/*
-			 * stop TID, if A-MPDU frames are still missing,
+			/* stop TID, if A-MPDU frames are still missing,
 			 * or whenever the queue is empty.
 			 */
 
@@ -1450,12 +1472,14 @@ void carl9170_op_tx(struct ieee80211_hw *hw,
 	struct ar9170 *ar = hw->priv;
 	struct ieee80211_tx_info *info;
 	struct ieee80211_sta *sta = control->sta;
+	struct ieee80211_vif *vif;
 	bool run;
 
 	if (unlikely(!IS_STARTED(ar)))
 		goto err_free;
 
 	info = IEEE80211_SKB_CB(skb);
+	vif = info->control.vif;
 
 	if (unlikely(carl9170_tx_prepare(ar, sta, skb)))
 		goto err_free;
@@ -1486,6 +1510,8 @@ void carl9170_op_tx(struct ieee80211_hw *hw,
 	} else {
 		unsigned int queue = skb_get_queue_mapping(skb);
 
+		carl9170_tx_get_rates(ar, vif, sta, skb);
+		carl9170_tx_apply_rateset(ar, info, skb);
 		skb_queue_tail(&ar->tx_pending[queue], skb);
 	}
 

^ permalink raw reply related

* RE: [PATCH v2 2/2] cfg80211/nl80211: Add packet coalesce support
From: Bing Zhao @ 2013-06-12 19:20 UTC (permalink / raw)
  To: Johannes Berg, Amitkumar Karwar
  Cc: linux-wireless@vger.kernel.org, Luis R. Rodriguez, Jouni Malinen,
	Vasanthakumar Thiagarajan, Senthil Balasubramanian,
	Luciano Coelho
In-Reply-To: <1370950378.8356.13.camel@jlt4.sipsolutions.net>

SGkgSm9oYW5uZXMsDQoNCj4gUGVyc29uYWxseSwgSSBzZWUgaXcgYXMgYSBiaXQgb2YgYSB0ZXN0
IHRvb2wgc28gSSdtIG5vdCB0b28gY29uY2VybmVkDQo+IGFib3V0IGl0cyBzb21ldGltZXMgb2Rk
IGNvbW1hbmQgbGluZSwgYnV0IEkga25vdyBnaXZpbmcgaXQgbG90cyBvZg0KPiB0aGluZ3MgY2Fu
IGJlIGF3a3dhcmQuIEZvciBUQ1Agd2FrZXVwLCBJJ3ZlIG1hZGUgaXQgcGFyc2UgYSBzbWFsbCBm
aWxlLA0KPiBtYXliZSB0aGF0J3MgYW4gb3B0aW9uIGhlcmUgYXMgd2VsbD8NCg0KWWVzLCB3ZSBj
YW4gcGFyc2UgYSBjb25maWd1cmUgZmlsZSBhcyB3ZWxsLiBUaGFua3MgZm9yIHRoZSBoaW50Lg0K
DQo+ID4gUGxlYXNlIGxldCB1cyBrbm93IGlmIHlvdSBwcmVmZXIgImNvYWxlc2NlIHNldCIgb3Zl
ciAiY29hbGVzY2UgYWRkIi4NCj4gDQo+IEkgd291bGQgbXVjaCBwcmVmZXIganVzdCBoYXZpbmcg
c2V0L2NsZWFyIG92ZXIgcGllY2V3aXNlIGNvbmZpZ3VyYXRpb24uDQoNCk9LLiBXZSB3aWxsIHRh
a2Ugc2V0L2NsZWFyIGFwcHJvYWNoIGluIHYzLg0KDQpUaGFua3MsDQpCaW5nDQo=

^ permalink raw reply

* RE: [PATCH] mwifiex: Add module parameter for regdomain
From: Bing Zhao @ 2013-06-12 19:01 UTC (permalink / raw)
  To: Ben Greear, Kalle Valo
  Cc: linux-wireless@vger.kernel.org, John W. Linville,
	Amitkumar Karwar, Avinash Patil, Yogesh Powar, Nishant Sarmukadam,
	Frank Huang, Paul Stewart
In-Reply-To: <51B8C41E.7050907@candelatech.com>


> >> "iw reg set XX" or "country_code=XX" in hostapd.conf is a *user* hint.
> >>
> >> What we need here is a *driver* hint. Furthermore, with a driver
> >> regulatory hint, the passive-scan and no-ibss flags are cleared so we
> >> can start AP with hostapd on 5G band.
> >
> > So it's a driver hint which is coming from user space via a module
> > parameter. IMHO you are abusing interfaces here. Is there any better way
> > to solve your problem?
> 
> It would be nice to have some way to do this for ath9k and other NICs
> as well.  Best I could come up with is a similar hack for ath9k.
> 
> I think part of the problem is that this config info needs to be
> available very early in the module loading/init logic, so it's
> too late to be configured using 'iw' or similar.

Exactly. regulatory_hint () needs to be called right after wiphy registration.

Thanks,
Bing

> 
> Thanks,
> Ben


^ permalink raw reply

* Re: [PATCH] carl9170: make use of the new rate control API
From: John W. Linville @ 2013-06-12 18:53 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: Johannes Berg, Thomas Hühn, linux-wireless, nbd
In-Reply-To: <201306112149.09768.chunkeey@googlemail.com>

On Tue, Jun 11, 2013 at 09:49:09PM +0200, Christian Lamparter wrote:
> On Tuesday, June 11, 2013 09:24:28 PM Johannes Berg wrote:
> > On Tue, 2013-06-11 at 21:17 +0200, Thomas Hühn wrote:
> > > Hi Christian,
> > > 
> > > I have not seen that patch in wireless-next, that's why I overlooked it... sorry.
> You are right and it's not in wireless-testing.git either. That's a bit odd.
> 
> John,
> 
> was this patch overlooked/lost or was there a problem with it?
> (Or: can you please put it into wireless-next)

No idea, but I don't seem to have it.  Can you resend it?

> > > > carl9170 already supports the new rate control API (Patch from 2013-04-23).
> > > > <http://permalink.gmane.org/gmane.linux.kernel.wireless.general/107657>
> > > > 
> > > > Can you please tell me what you think is missing?
> > > > 
> > > 
> > > You patch looks good to me.
> > > As I just saw an ath9k patch for rcu protection when ieee80211_get_tx_rates() is called.
> > > Should this be done in carl9170 as well ?
> > 
> > I think that patch is wrong actually, probably should just do the rcu
> > protection inside the function. However the patch is completely wrong
> > anyway (C isn't python) so ...
> Uh, that's confusing. We are now talking about the patch from Thomas, right?
> If so: the previous "new rate control api" feature patch for carl9170 should
> be fine in this regard.
> 
> Regards,
> 	Chr
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

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

^ permalink raw reply

* Re: [PATCH] mwifiex: Add module parameter for regdomain
From: Ben Greear @ 2013-06-12 18:55 UTC (permalink / raw)
  To: Kalle Valo
  Cc: Bing Zhao, linux-wireless@vger.kernel.org, John W. Linville,
	Amitkumar Karwar, Avinash Patil, Yogesh Powar, Nishant Sarmukadam,
	Frank Huang, Paul Stewart
In-Reply-To: <8738sn2mcf.fsf@purkki.adurom.net>

On 06/12/2013 11:52 AM, Kalle Valo wrote:
> Bing Zhao <bzhao@marvell.com> writes:
>
>> Hi Kalle,
>>
>>>> From: Avinash Patil <patila@marvell.com>
>>>>
>>>> Allow a regulatory domain country code to be specified at boot
>>>> using a module argument.  This overrides the firmware regulatory
>>>> mode.
>>>>
>>>> This patch also enables uAP to operate in 11a mode with hostapd.
>>>>
>>>> Signed-off-by: Avinash Patil <patila@marvell.com>
>>>> Signed-off-by: Paul Stewart <pstew@chromium.org>
>>>> Signed-off-by: Bing Zhao <bzhao@marvell.com>
>>>
>>> This looks ugly. Why can't you use the proper nl80211 interface and
>>> instead want to add a driver specific hack?
>>
>> "iw reg set XX" or "country_code=XX" in hostapd.conf is a *user* hint.
>>
>> What we need here is a *driver* hint. Furthermore, with a driver
>> regulatory hint, the passive-scan and no-ibss flags are cleared so we
>> can start AP with hostapd on 5G band.
>
> So it's a driver hint which is coming from user space via a module
> parameter. IMHO you are abusing interfaces here. Is there any better way
> to solve your problem?

It would be nice to have some way to do this for ath9k and other NICs
as well.  Best I could come up with is a similar hack for ath9k.

I think part of the problem is that this config info needs to be
available very early in the module loading/init logic, so it's
too late to be configured using 'iw' or similar.

Thanks,
Ben


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


^ permalink raw reply

* Re: [PATCH] mwifiex: Add module parameter for regdomain
From: Kalle Valo @ 2013-06-12 18:52 UTC (permalink / raw)
  To: Bing Zhao
  Cc: linux-wireless@vger.kernel.org, John W. Linville,
	Amitkumar Karwar, Avinash Patil, Yogesh Powar, Nishant Sarmukadam,
	Frank Huang, Paul Stewart
In-Reply-To: <477F20668A386D41ADCC57781B1F70430EA268B457@SC-VEXCH1.marvell.com>

Bing Zhao <bzhao@marvell.com> writes:

> Hi Kalle,
>
>> > From: Avinash Patil <patila@marvell.com>
>> >
>> > Allow a regulatory domain country code to be specified at boot
>> > using a module argument.  This overrides the firmware regulatory
>> > mode.
>> >
>> > This patch also enables uAP to operate in 11a mode with hostapd.
>> >
>> > Signed-off-by: Avinash Patil <patila@marvell.com>
>> > Signed-off-by: Paul Stewart <pstew@chromium.org>
>> > Signed-off-by: Bing Zhao <bzhao@marvell.com>
>> 
>> This looks ugly. Why can't you use the proper nl80211 interface and
>> instead want to add a driver specific hack?
>
> "iw reg set XX" or "country_code=XX" in hostapd.conf is a *user* hint.
>
> What we need here is a *driver* hint. Furthermore, with a driver
> regulatory hint, the passive-scan and no-ibss flags are cleared so we
> can start AP with hostapd on 5G band.

So it's a driver hint which is coming from user space via a module
parameter. IMHO you are abusing interfaces here. Is there any better way
to solve your problem?

-- 
Kalle Valo

^ permalink raw reply

* Pull request: ath6kl 20130612
From: Kalle Valo @ 2013-06-12 18:38 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, ath6kl-devel

Hi John,

here are few simple patches for ath6kl. We have a suspend crash fix for
USB from Shafi, use of mac_pton(), a compiler warning fix and a fix for
module initialisation error path.

Kalle

The following changes since commit 3e817f086f06069a23b797ee2279bbae638d5edc:

  cw1200: remove unused including <linux/version.h> (2013-05-30 14:45:25 -0400)

are available in the git repository at:

  git://github.com/kvalo/ath6kl.git for-linville

for you to fetch changes up to 37291fc61253cd34db40b7a60be4497db776db41:

  ath6kl: Unify sg_sz and buf_sz in ath6kl_sdio_alloc_prep_scat_req() (2013-06-01 15:16:33 +0300)

----------------------------------------------------------------
Andy Shevchenko (1):
      wireless: ath6kl: re-use native helper to parse MAC

Geert Uytterhoeven (1):
      ath6kl: Unify sg_sz and buf_sz in ath6kl_sdio_alloc_prep_scat_req()

Mohammed Shafi Shajakhan (2):
      ath6kl: Rename USB driver's suspend/resume/reset_resume
      ath6kl: Fix a suspend/resume crash in AR6004 USB

Raja Mani (1):
      ath6kl: Check wmi ready event status before validating abi version

 drivers/net/wireless/ath/ath6kl/debug.c |    8 +------
 drivers/net/wireless/ath/ath6kl/init.c  |   14 ++++++------
 drivers/net/wireless/ath/ath6kl/sdio.c  |   12 +++++------
 drivers/net/wireless/ath/ath6kl/usb.c   |   36 +++++++++++++++++++++++--------
 4 files changed, 41 insertions(+), 29 deletions(-)

^ permalink raw reply

* Re: [GIT] [3.10] NFC fixes
From: John W. Linville @ 2013-06-12 18:22 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: Linux Wireless, Linux NFC
In-Reply-To: <20130606152019.GT4793@zurbaran>

Given recent events, I'm not sure that this is really acceptable as
a fix request.  The service bit and endianness in particular don't
sound like they are addressing big problems, and the other two don't
sound like they are really fixing any regressions either.

Can these wait for 3.11?

John

On Thu, Jun 06, 2013 at 05:20:19PM +0200, Samuel Ortiz wrote:
> Hi John,
> 
> This is the 2nd NFC pull request for 3.10.
> 
> I wish this one could have been part of the first one, but we came back from
> the NFC plugfest with a few more LLCP fixes:
> 
> - The well known services bitmask was sent with the wrong endianness and with
>   the first bit not set, which goes against the LLCP specifications. This
>   won't prevent most use cases and tests to pass, only picky implementations
>   seem to care about the WKS correctness.
> 
> - We were ignoring RNRs and were sending our pending frames regardless. We
>   should just re-queue them and send a SYMM instead.
> 
> - Non blocking LLCP connections were not handled properly as we found out
>   after implementing it from neard. Applications were immediatly woken up with
>   a SIGHUP and connection failed. This is fixed now, allowing us to have a
>   fully asynchronous NFC userspace daemon.
> 
> Thanks in advance for pulling them in.
> 
> The following changes since commit cee6dfa25831e0daac52fc582a04a7204f886220:
> 
>   Revert "ath9k_hw: Update rx gain initval to improve rx sensitivity" (2013-06-05 10:42:29 -0400)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-fixes.git tags/nfc-fixes-3.10-2
> 
> for you to fetch changes up to fcd335b0010aeafb6e3dfd46360778ce59e1e201:
> 
>   NFC: llcp: Fix the well known services endianness (2013-06-06 16:43:51 +0200)
> 
> ----------------------------------------------------------------
> Samuel Ortiz (4):
>       NFC: llcp: Fix non blocking sockets connections
>       NFC: llcp: Do not send pending Tx frames when the remote is not ready
>       NFC: llcp: Set the LLC Link Management well known service bit
>       NFC: llcp: Fix the well known services endianness
> 
>  net/nfc/llcp.h      |    1 +
>  net/nfc/llcp_core.c |    8 ++++++--
>  net/nfc/llcp_sock.c |    8 +++++---
>  3 files changed, 12 insertions(+), 5 deletions(-)
> -- 
> Intel Open Source Technology Centre
> http://oss.intel.com/
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

-- 
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

* kmemleak report related to ieee80211_start_tx_ba_session, tid_start_tx locking issues?
From: Ben Greear @ 2013-06-12 18:21 UTC (permalink / raw)
  To: linux-wireless@vger.kernel.org

This is on 3.9.5+

I see a fair amount of these.  Once again, the locking is tricky
for my poor brain, but I am suspicious of this part of things.

It seems that ampdu_mlme.mtx is used to protect the tid
arrays (although sta->lock also applies to part of it).

In ieee80211_start_tx_ba_session we are accessing and assigning the tid_start_tx
without holding the ampdu_mlme.mtx mutex.

	spin_lock_bh(&sta->lock);
.....
	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
	/* check if the TID is not in aggregation flow already */
	if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {

....

	/*
	 * Finally, assign it to the start array; the work item will
	 * collect it and move it to the normal array.
	 */
	sta->ampdu_mlme.tid_start_tx[tid] = tid_tx;


Elsewhere, in ieee80211_ba_session_work, we access the tid_start_tx
without the sta->lock held, but with the ampdu_mlme.mtx held.

I think we should probably hold ampdu_mlme.mtx in ieee80211_start_tx_ba_session
or make sure we hold sta->lock in ieee80211_ba_session_work.


unreferenced object 0xffff880219b4de40 (size 192):
   comm "softirq", pid 0, jiffies 4296416789 (age 1257.971s)
   hex dump (first 32 bytes):
     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
   backtrace:
     [<ffffffff815bc02c>] kmemleak_alloc+0x73/0x98
     [<ffffffff8117d4b4>] slab_post_alloc_hook+0x28/0x2a
     [<ffffffff8117f4a6>] kmem_cache_alloc_trace+0xa5/0xcc
     [<ffffffffa0365221>] ieee80211_start_tx_ba_session+0x24b/0x360 [mac80211]
     [<ffffffffa03a98f3>] minstrel_ht_tx_status+0x79a/0x7a9 [mac80211]
     [<ffffffffa035d1cd>] ieee80211_tx_status+0x3af/0x947 [mac80211]
     [<ffffffffa06e86fa>] ath_txq_unlock_complete+0xb0/0xbb [ath9k]
     [<ffffffffa06e8992>] ath_tx_edma_tasklet+0x28d/0x2a4 [ath9k]
     [<ffffffffa06e33cd>] ath9k_tasklet+0x111/0x150 [ath9k]
     [<ffffffff8109d6d3>] tasklet_action+0x7d/0xcc
     [<ffffffff8109db2c>] __do_softirq+0x114/0x254
     [<ffffffff8109dcfe>] irq_exit+0x4b/0xa8
     [<ffffffff815d481d>] do_IRQ+0x9d/0xb4
     [<ffffffff815cc8ed>] ret_from_intr+0x0/0x15
     [<ffffffff814c8efb>] cpuidle_enter_tk+0x10/0x12
     [<ffffffff814c89b5>] cpuidle_enter_state+0x17/0x3f

Thanks,
Ben

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


^ permalink raw reply

* Pull request: ath10k 20130612
From: Kalle Valo @ 2013-06-12 18:15 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, ath10k-devel

Hi John,

here's the pull request for ath10k. This is the same version I submitted
June 1st for the second review, now it's just one big commit with the
necessary changes to Makefile and Kconfig in drivers/net/wireless/ath.

Please let me know if there are any problems.

Kalle

The following changes since commit 8b3e7be437a6b62118d0485ad971e724afe23fdf:

  cw1200: Fix an assorted pile of checkpatch warnings. (2013-06-11 12:48:10 -0400)

are available in the git repository at:

  git://github.com/kvalo/ath6kl.git for-linville-ath10k

for you to fetch changes up to 5e3dd157d7e70f0e3cea3f2573ed69fb156a19d5:

  ath10k: mac80211 driver for Qualcomm Atheros 802.11ac CQA98xx devices (2013-06-12 20:52:10 +0300)

----------------------------------------------------------------
Kalle Valo (1):
      ath10k: mac80211 driver for Qualcomm Atheros 802.11ac CQA98xx devices

 drivers/net/wireless/ath/Kconfig            |    1 +
 drivers/net/wireless/ath/Makefile           |    1 +
 drivers/net/wireless/ath/ath10k/Kconfig     |   39 +
 drivers/net/wireless/ath/ath10k/Makefile    |   20 +
 drivers/net/wireless/ath/ath10k/bmi.c       |  295 +++
 drivers/net/wireless/ath/ath10k/bmi.h       |  224 ++
 drivers/net/wireless/ath/ath10k/ce.c        | 1189 +++++++++++
 drivers/net/wireless/ath/ath10k/ce.h        |  516 +++++
 drivers/net/wireless/ath/ath10k/core.c      |  665 ++++++
 drivers/net/wireless/ath/ath10k/core.h      |  369 ++++
 drivers/net/wireless/ath/ath10k/debug.c     |  503 +++++
 drivers/net/wireless/ath/ath10k/debug.h     |   90 +
 drivers/net/wireless/ath/ath10k/hif.h       |  137 ++
 drivers/net/wireless/ath/ath10k/htc.c       | 1000 +++++++++
 drivers/net/wireless/ath/ath10k/htc.h       |  368 ++++
 drivers/net/wireless/ath/ath10k/htt.c       |  152 ++
 drivers/net/wireless/ath/ath10k/htt.h       | 1338 ++++++++++++
 drivers/net/wireless/ath/ath10k/htt_rx.c    | 1167 ++++++++++
 drivers/net/wireless/ath/ath10k/htt_tx.c    |  510 +++++
 drivers/net/wireless/ath/ath10k/hw.h        |  304 +++
 drivers/net/wireless/ath/ath10k/mac.c       | 3066 +++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/mac.h       |   61 +
 drivers/net/wireless/ath/ath10k/pci.c       | 2506 ++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/pci.h       |  355 ++++
 drivers/net/wireless/ath/ath10k/rx_desc.h   |  990 +++++++++
 drivers/net/wireless/ath/ath10k/targaddrs.h |  449 ++++
 drivers/net/wireless/ath/ath10k/trace.c     |   20 +
 drivers/net/wireless/ath/ath10k/trace.h     |  170 ++
 drivers/net/wireless/ath/ath10k/txrx.c      |  417 ++++
 drivers/net/wireless/ath/ath10k/txrx.h      |   39 +
 drivers/net/wireless/ath/ath10k/wmi.c       | 2081 ++++++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi.h       | 3052 ++++++++++++++++++++++++++
 32 files changed, 22094 insertions(+)
 create mode 100644 drivers/net/wireless/ath/ath10k/Kconfig
 create mode 100644 drivers/net/wireless/ath/ath10k/Makefile
 create mode 100644 drivers/net/wireless/ath/ath10k/bmi.c
 create mode 100644 drivers/net/wireless/ath/ath10k/bmi.h
 create mode 100644 drivers/net/wireless/ath/ath10k/ce.c
 create mode 100644 drivers/net/wireless/ath/ath10k/ce.h
 create mode 100644 drivers/net/wireless/ath/ath10k/core.c
 create mode 100644 drivers/net/wireless/ath/ath10k/core.h
 create mode 100644 drivers/net/wireless/ath/ath10k/debug.c
 create mode 100644 drivers/net/wireless/ath/ath10k/debug.h
 create mode 100644 drivers/net/wireless/ath/ath10k/hif.h
 create mode 100644 drivers/net/wireless/ath/ath10k/htc.c
 create mode 100644 drivers/net/wireless/ath/ath10k/htc.h
 create mode 100644 drivers/net/wireless/ath/ath10k/htt.c
 create mode 100644 drivers/net/wireless/ath/ath10k/htt.h
 create mode 100644 drivers/net/wireless/ath/ath10k/htt_rx.c
 create mode 100644 drivers/net/wireless/ath/ath10k/htt_tx.c
 create mode 100644 drivers/net/wireless/ath/ath10k/hw.h
 create mode 100644 drivers/net/wireless/ath/ath10k/mac.c
 create mode 100644 drivers/net/wireless/ath/ath10k/mac.h
 create mode 100644 drivers/net/wireless/ath/ath10k/pci.c
 create mode 100644 drivers/net/wireless/ath/ath10k/pci.h
 create mode 100644 drivers/net/wireless/ath/ath10k/rx_desc.h
 create mode 100644 drivers/net/wireless/ath/ath10k/targaddrs.h
 create mode 100644 drivers/net/wireless/ath/ath10k/trace.c
 create mode 100644 drivers/net/wireless/ath/ath10k/trace.h
 create mode 100644 drivers/net/wireless/ath/ath10k/txrx.c
 create mode 100644 drivers/net/wireless/ath/ath10k/txrx.h
 create mode 100644 drivers/net/wireless/ath/ath10k/wmi.c
 create mode 100644 drivers/net/wireless/ath/ath10k/wmi.h


^ permalink raw reply

* RE: [PATCH] mwifiex: Add module parameter for regdomain
From: Bing Zhao @ 2013-06-12 17:43 UTC (permalink / raw)
  To: Kalle Valo
  Cc: linux-wireless@vger.kernel.org, John W. Linville,
	Amitkumar Karwar, Avinash Patil, Yogesh Powar, Nishant Sarmukadam,
	Frank Huang, Paul Stewart
In-Reply-To: <877ghz3il6.fsf@purkki.adurom.net>

Hi Kalle,

> > From: Avinash Patil <patila@marvell.com>
> >
> > Allow a regulatory domain country code to be specified at boot
> > using a module argument.  This overrides the firmware regulatory
> > mode.
> >
> > This patch also enables uAP to operate in 11a mode with hostapd.
> >
> > Signed-off-by: Avinash Patil <patila@marvell.com>
> > Signed-off-by: Paul Stewart <pstew@chromium.org>
> > Signed-off-by: Bing Zhao <bzhao@marvell.com>
> 
> This looks ugly. Why can't you use the proper nl80211 interface and
> instead want to add a driver specific hack?

"iw reg set XX" or "country_code=XX" in hostapd.conf is a *user* hint.
What we need here is a *driver* hint.
Furthermore, with a driver regulatory hint, the passive-scan and no-ibss flags are cleared so we can start AP with hostapd on 5G band.

Thanks,
Bing

> 
> --
> Kalle Valo

^ permalink raw reply

* pull request: wireless 2013-06-12
From: John W. Linville @ 2013-06-12 15:09 UTC (permalink / raw)
  To: davem; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <20130606190929.GB18827@tuxdriver.com>

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

Dave,

For now I have dropped the mac80211 tree from this request.
We are developing a little backlog of fixes and I would like to
avoid introducing any more uncertainty to this pull request for the
3.10 stream.  All the other bits are the same as what was in the
2013-06-06 request, including the ath9k fixes intended to address
the problems observed by Linus w/ his Pixel, and a CVE fix for a
potential security issue in the b43 driver.

Regarding the wl12xx bits, Luca says:

"Here are three patches that I'd like to get into 3.10.  Two of them, by
me, are related to the firmware version checks in our driver.  Without
them, the firmwares fail to load.  The other one, by Eliad, fixes a typo
bug in our 5GHz scanning code."

And as for the Bluetooth bits, Gustavo says:

"The following patches are important bug fixes for 3.10, plus the
support for a new device. We do have three fixes from Johan. The first
one is a fix to avoid LE-only devices to rely on the (inexistent)
extended features data. The second patch fixes length checks on
incoming L2CAP signalling PDUs so we can discard PDU whose size
doesn't match the one reported in the header.  The last one fixes
the handling of power on failures, we now report proper errors to
mgmt when hci_dev_open()."

Along with that...

Larry Finger corrects an rtlwifi problem that caused some devices to
refuse to connect to non-WPA2 networks if the device had previously
assocated with a WPA2 network.  He also adds a one-line fix to prevent
false reports from kmemleak.

Mark A. Greer fixes an out of bounds array access in mwifiex.

Felix Fietkau reverts an earlier ath9k initval patch that reduced rx
sensitivity in a number of ath9k devices with no corresponding benefit.

Kees Cook fixes a potential uid-0 to ring-0 escalation in b43
(CVE-2013-2852).

Sujith Manoharan turns-off powersave mode by default for ath9k, and
also defaults ath9k to use the minstrel_ht rate control algorithm.
Both of these are believed to contribute to greater stability/usability
of ath9k in real-world situations.

Yijing Wang fixes an iwlegacy build error for il_pm_ops if CONFIG_PM
is set but CONFIG_PM_SLEEP is not set.

Please let me know if there are any problems!

Thanks,

John

---

The following changes since commit b79462a8b9f9a452edc20c64a70a89ba3b0a6a88:

  team: fix checks in team_get_first_port_txable_rcu() (2013-06-12 00:56:27 -0700)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git for-davem

for you to fetch changes up to 42d887a68013b0a04f7b8ebfa4999a8d5df6775c:

  Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless into for-davem (2013-06-12 10:57:04 -0400)

----------------------------------------------------------------

Bing Zhao (1):
      Bluetooth: btmrvl: support Marvell Bluetooth device SD8897

Eliad Peller (1):
      wl12xx/wl18xx: scan all 5ghz channels

Felix Fietkau (1):
      Revert "ath9k_hw: Update rx gain initval to improve rx sensitivity"

Johan Hedberg (3):
      Bluetooth: Fix checks for LE support on LE-only controllers
      Bluetooth: Fix missing length checks for L2CAP signalling PDUs
      Bluetooth: Fix mgmt handling of power on failures

John W. Linville (1):
      Merge branch 'master' of git://git.kernel.org/.../linville/wireless into for-davem

Kees Cook (1):
      b43: stop format string leaking into error msgs

Larry Finger (2):
      rtlwifi: rtl8192cu: Fix problem in connecting to WEP or WPA(1) networks
      rtlwifi: Fix a false leak indication for PCI devices

Luciano Coelho (2):
      wl12xx: fix minimum required firmware version for wl127x multirole
      wl12xx: increase minimum singlerole firmware version required

Mark A. Greer (1):
      mwifiex: debugfs: Fix out of bounds array access

Sujith Manoharan (2):
      ath9k: Disable PowerSave by default
      ath9k: Use minstrel rate control by default

Yijing Wang (1):
      net: wireless: iwlegacy: fix build error for il_pm_ops

 drivers/bluetooth/Kconfig                          |   4 +-
 drivers/bluetooth/btmrvl_sdio.c                    |  28 +++++
 drivers/net/wireless/ath/ath9k/Kconfig             |  10 +-
 drivers/net/wireless/ath/ath9k/Makefile            |   2 +-
 .../net/wireless/ath/ath9k/ar9003_2p2_initvals.h   |  10 +-
 drivers/net/wireless/ath/ath9k/init.c              |   7 +-
 drivers/net/wireless/ath/ath9k/rc.h                |   2 +-
 drivers/net/wireless/b43/main.c                    |   2 +-
 drivers/net/wireless/iwlegacy/common.h             |   6 +-
 drivers/net/wireless/mwifiex/debugfs.c             |  22 +++-
 drivers/net/wireless/rtlwifi/pci.c                 |   1 +
 drivers/net/wireless/rtlwifi/rtl8192cu/hw.c        | 134 +++++++++++++++------
 drivers/net/wireless/rtlwifi/rtl8192cu/hw.h        |   4 -
 drivers/net/wireless/rtlwifi/rtl8192cu/mac.c       |  18 ++-
 drivers/net/wireless/rtlwifi/rtl8192cu/sw.c        |   4 +-
 drivers/net/wireless/rtlwifi/rtl8192cu/sw.h        |   3 +
 drivers/net/wireless/rtlwifi/usb.c                 |  13 ++
 drivers/net/wireless/rtlwifi/wifi.h                |   4 +
 drivers/net/wireless/ti/wl12xx/scan.c              |   2 +-
 drivers/net/wireless/ti/wl12xx/wl12xx.h            |   6 +-
 drivers/net/wireless/ti/wl18xx/scan.c              |   2 +-
 include/net/bluetooth/hci_core.h                   |   1 +
 include/net/bluetooth/mgmt.h                       |   1 +
 net/bluetooth/hci_core.c                           |   6 +-
 net/bluetooth/l2cap_core.c                         |  70 ++++++++---
 net/bluetooth/mgmt.c                               |  23 +++-
 net/bluetooth/smp.c                                |   4 +-
 27 files changed, 294 insertions(+), 95 deletions(-)

diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index fdfd61a..11a6104 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -201,7 +201,7 @@ config BT_MRVL
 	  The core driver to support Marvell Bluetooth devices.
 
 	  This driver is required if you want to support
-	  Marvell Bluetooth devices, such as 8688/8787/8797.
+	  Marvell Bluetooth devices, such as 8688/8787/8797/8897.
 
 	  Say Y here to compile Marvell Bluetooth driver
 	  into the kernel or say M to compile it as module.
@@ -214,7 +214,7 @@ config BT_MRVL_SDIO
 	  The driver for Marvell Bluetooth chipsets with SDIO interface.
 
 	  This driver is required if you want to use Marvell Bluetooth
-	  devices with SDIO interface. Currently SD8688/SD8787/SD8797
+	  devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8897
 	  chipsets are supported.
 
 	  Say Y here to compile support for Marvell BT-over-SDIO driver
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index c63488c..13693b7 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -82,6 +82,23 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
 	.io_port_2 = 0x7a,
 };
 
+static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
+	.cfg = 0x00,
+	.host_int_mask = 0x02,
+	.host_intstatus = 0x03,
+	.card_status = 0x50,
+	.sq_read_base_addr_a0 = 0x60,
+	.sq_read_base_addr_a1 = 0x61,
+	.card_revision = 0xbc,
+	.card_fw_status0 = 0xc0,
+	.card_fw_status1 = 0xc1,
+	.card_rx_len = 0xc2,
+	.card_rx_unit = 0xc3,
+	.io_port_0 = 0xd8,
+	.io_port_1 = 0xd9,
+	.io_port_2 = 0xda,
+};
+
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
 	.helper		= "mrvl/sd8688_helper.bin",
 	.firmware	= "mrvl/sd8688.bin",
@@ -103,6 +120,13 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
 	.sd_blksz_fw_dl	= 256,
 };
 
+static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
+	.helper		= NULL,
+	.firmware	= "mrvl/sd8897_uapsta.bin",
+	.reg		= &btmrvl_reg_88xx,
+	.sd_blksz_fw_dl	= 256,
+};
+
 static const struct sdio_device_id btmrvl_sdio_ids[] = {
 	/* Marvell SD8688 Bluetooth device */
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
@@ -116,6 +140,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = {
 	/* Marvell SD8797 Bluetooth device */
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
 			.driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
+	/* Marvell SD8897 Bluetooth device */
+	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E),
+			.driver_data = (unsigned long) &btmrvl_sdio_sd8897 },
 
 	{ }	/* Terminating entry */
 };
@@ -1194,3 +1221,4 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
 MODULE_FIRMWARE("mrvl/sd8688.bin");
 MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
 MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
+MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index f3dc124..3c2cbc9 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -92,13 +92,17 @@ config ATH9K_MAC_DEBUG
 	  This option enables collection of statistics for Rx/Tx status
 	  data and some other MAC related statistics
 
-config ATH9K_RATE_CONTROL
+config ATH9K_LEGACY_RATE_CONTROL
 	bool "Atheros ath9k rate control"
 	depends on ATH9K
-	default y
+	default n
 	---help---
 	  Say Y, if you want to use the ath9k specific rate control
-	  module instead of minstrel_ht.
+	  module instead of minstrel_ht. Be warned that there are various
+	  issues with the ath9k RC and minstrel is a more robust algorithm.
+	  Note that even if this option is selected, "ath9k_rate_control"
+	  has to be passed to mac80211 using the module parameter,
+	  ieee80211_default_rc_algo.
 
 config ATH9K_HTC
        tristate "Atheros HTC based wireless cards support"
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 2ad8f94..75ee9e7 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -8,7 +8,7 @@ ath9k-y +=	beacon.o \
 		antenna.o
 
 ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
-ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
+ath9k-$(CONFIG_ATH9K_LEGACY_RATE_CONTROL) += rc.o
 ath9k-$(CONFIG_ATH9K_PCI) += pci.o
 ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
 ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index db5ffad..7546b9a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -958,11 +958,11 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
 	{0x0000a074, 0x00000000},
 	{0x0000a078, 0x00000000},
 	{0x0000a07c, 0x00000000},
-	{0x0000a080, 0x1a1a1a1a},
-	{0x0000a084, 0x1a1a1a1a},
-	{0x0000a088, 0x1a1a1a1a},
-	{0x0000a08c, 0x1a1a1a1a},
-	{0x0000a090, 0x171a1a1a},
+	{0x0000a080, 0x22222229},
+	{0x0000a084, 0x1d1d1d1d},
+	{0x0000a088, 0x1d1d1d1d},
+	{0x0000a08c, 0x1d1d1d1d},
+	{0x0000a090, 0x171d1d1d},
 	{0x0000a094, 0x11111717},
 	{0x0000a098, 0x00030311},
 	{0x0000a09c, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index aba4151..2ba4945 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -787,8 +787,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
 	hw->wiphy->iface_combinations = if_comb;
 	hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
 
-	if (AR_SREV_5416(sc->sc_ah))
-		hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+	hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
 	hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
@@ -830,10 +829,6 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
 	sc->ant_rx = hw->wiphy->available_antennas_rx;
 	sc->ant_tx = hw->wiphy->available_antennas_tx;
 
-#ifdef CONFIG_ATH9K_RATE_CONTROL
-	hw->rate_control_algorithm = "ath9k_rate_control";
-#endif
-
 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
 		hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
 			&sc->sbands[IEEE80211_BAND_2GHZ];
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index 267dbfc..b9a8738 100644
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -231,7 +231,7 @@ static inline void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
 }
 #endif
 
-#ifdef CONFIG_ATH9K_RATE_CONTROL
+#ifdef CONFIG_ATH9K_LEGACY_RATE_CONTROL
 int ath_rate_control_register(void);
 void ath_rate_control_unregister(void);
 #else
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 6dd07e2..a95b77a 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -2458,7 +2458,7 @@ static void b43_request_firmware(struct work_struct *work)
 	for (i = 0; i < B43_NR_FWTYPES; i++) {
 		errmsg = ctx->errors[i];
 		if (strlen(errmsg))
-			b43err(dev->wl, errmsg);
+			b43err(dev->wl, "%s", errmsg);
 	}
 	b43_print_fw_helptext(dev->wl, 1);
 	goto out;
diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h
index f8246f2..4caaf52 100644
--- a/drivers/net/wireless/iwlegacy/common.h
+++ b/drivers/net/wireless/iwlegacy/common.h
@@ -1832,16 +1832,16 @@ u32 il_usecs_to_beacons(struct il_priv *il, u32 usec, u32 beacon_interval);
 __le32 il_add_beacon_time(struct il_priv *il, u32 base, u32 addon,
 			  u32 beacon_interval);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 extern const struct dev_pm_ops il_pm_ops;
 
 #define IL_LEGACY_PM_OPS	(&il_pm_ops)
 
-#else /* !CONFIG_PM */
+#else /* !CONFIG_PM_SLEEP */
 
 #define IL_LEGACY_PM_OPS	NULL
 
-#endif /* !CONFIG_PM */
+#endif /* !CONFIG_PM_SLEEP */
 
 /*****************************************************
 *  Error Handling Debugging
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
index 753b568..a5f9875 100644
--- a/drivers/net/wireless/mwifiex/debugfs.c
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -26,10 +26,17 @@
 static struct dentry *mwifiex_dfs_dir;
 
 static char *bss_modes[] = {
-	"Unknown",
-	"Ad-hoc",
-	"Managed",
-	"Auto"
+	"UNSPECIFIED",
+	"ADHOC",
+	"STATION",
+	"AP",
+	"AP_VLAN",
+	"WDS",
+	"MONITOR",
+	"MESH_POINT",
+	"P2P_CLIENT",
+	"P2P_GO",
+	"P2P_DEVICE",
 };
 
 /* size/addr for mwifiex_debug_info */
@@ -200,7 +207,12 @@ mwifiex_info_read(struct file *file, char __user *ubuf,
 	p += sprintf(p, "driver_version = %s", fmt);
 	p += sprintf(p, "\nverext = %s", priv->version_str);
 	p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
-	p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
+
+	if (info.bss_mode >= ARRAY_SIZE(bss_modes))
+		p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode);
+	else
+		p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
+
 	p += sprintf(p, "media_state=\"%s\"\n",
 		     (!priv->media_connected ? "Disconnected" : "Connected"));
 	p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr);
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 999ffc1..c97e9d3 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -764,6 +764,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
 				 "can't alloc skb for rx\n");
 			goto done;
 		}
+		kmemleak_not_leak(new_skb);
 
 		pci_unmap_single(rtlpci->pdev,
 				 *((dma_addr_t *) skb->cb),
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
index 3d0498e..189ba12 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
@@ -1973,26 +1973,35 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 	}
 }
 
-void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
-				   struct ieee80211_sta *sta,
-				   u8 rssi_level)
+static void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
+					  struct ieee80211_sta *sta)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	u32 ratr_value = (u32) mac->basic_rates;
-	u8 *mcsrate = mac->mcs;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u32 ratr_value;
 	u8 ratr_index = 0;
 	u8 nmode = mac->ht_enable;
-	u8 mimo_ps = 1;
-	u16 shortgi_rate = 0;
-	u32 tmp_ratr_value = 0;
+	u8 mimo_ps = IEEE80211_SMPS_OFF;
+	u16 shortgi_rate;
+	u32 tmp_ratr_value;
 	u8 curtxbw_40mhz = mac->bw_40;
-	u8 curshortgi_40mhz = mac->sgi_40;
-	u8 curshortgi_20mhz = mac->sgi_20;
+	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+			       1 : 0;
+	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+			       1 : 0;
 	enum wireless_mode wirelessmode = mac->mode;
 
-	ratr_value |= ((*(u16 *) (mcsrate))) << 12;
+	if (rtlhal->current_bandtype == BAND_ON_5G)
+		ratr_value = sta->supp_rates[1] << 4;
+	else
+		ratr_value = sta->supp_rates[0];
+	if (mac->opmode == NL80211_IFTYPE_ADHOC)
+		ratr_value = 0xfff;
+
+	ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+			sta->ht_cap.mcs.rx_mask[0] << 12);
 	switch (wirelessmode) {
 	case WIRELESS_MODE_B:
 		if (ratr_value & 0x0000000c)
@@ -2006,7 +2015,7 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
 	case WIRELESS_MODE_N_24G:
 	case WIRELESS_MODE_N_5G:
 		nmode = 1;
-		if (mimo_ps == 0) {
+		if (mimo_ps == IEEE80211_SMPS_STATIC) {
 			ratr_value &= 0x0007F005;
 		} else {
 			u32 ratr_mask;
@@ -2016,8 +2025,7 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
 				ratr_mask = 0x000ff005;
 			else
 				ratr_mask = 0x0f0ff005;
-			if (curtxbw_40mhz)
-				ratr_mask |= 0x00000010;
+
 			ratr_value &= ratr_mask;
 		}
 		break;
@@ -2026,41 +2034,74 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
 			ratr_value &= 0x000ff0ff;
 		else
 			ratr_value &= 0x0f0ff0ff;
+
 		break;
 	}
+
 	ratr_value &= 0x0FFFFFFF;
-	if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) ||
-	    (!curtxbw_40mhz && curshortgi_20mhz))) {
+
+	if (nmode && ((curtxbw_40mhz &&
+			 curshortgi_40mhz) || (!curtxbw_40mhz &&
+					       curshortgi_20mhz))) {
+
 		ratr_value |= 0x10000000;
 		tmp_ratr_value = (ratr_value >> 12);
+
 		for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
 			if ((1 << shortgi_rate) & tmp_ratr_value)
 				break;
 		}
+
 		shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
-			       (shortgi_rate << 4) | (shortgi_rate);
+		    (shortgi_rate << 4) | (shortgi_rate);
 	}
+
 	rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value);
+
+	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "%x\n",
+		 rtl_read_dword(rtlpriv, REG_ARFR0));
 }
 
-void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
+static void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw,
+					 struct ieee80211_sta *sta,
+					 u8 rssi_level)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	u32 ratr_bitmap = (u32) mac->basic_rates;
-	u8 *p_mcsrate = mac->mcs;
-	u8 ratr_index = 0;
-	u8 curtxbw_40mhz = mac->bw_40;
-	u8 curshortgi_40mhz = mac->sgi_40;
-	u8 curshortgi_20mhz = mac->sgi_20;
-	enum wireless_mode wirelessmode = mac->mode;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_sta_info *sta_entry = NULL;
+	u32 ratr_bitmap;
+	u8 ratr_index;
+	u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0;
+	u8 curshortgi_40mhz = curtxbw_40mhz &&
+			      (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+				1 : 0;
+	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+				1 : 0;
+	enum wireless_mode wirelessmode = 0;
 	bool shortgi = false;
 	u8 rate_mask[5];
 	u8 macid = 0;
-	u8 mimops = 1;
-
-	ratr_bitmap |= (p_mcsrate[1] << 20) | (p_mcsrate[0] << 12);
+	u8 mimo_ps = IEEE80211_SMPS_OFF;
+
+	sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+	wirelessmode = sta_entry->wireless_mode;
+	if (mac->opmode == NL80211_IFTYPE_STATION ||
+	    mac->opmode == NL80211_IFTYPE_MESH_POINT)
+		curtxbw_40mhz = mac->bw_40;
+	else if (mac->opmode == NL80211_IFTYPE_AP ||
+		mac->opmode == NL80211_IFTYPE_ADHOC)
+		macid = sta->aid + 1;
+
+	if (rtlhal->current_bandtype == BAND_ON_5G)
+		ratr_bitmap = sta->supp_rates[1] << 4;
+	else
+		ratr_bitmap = sta->supp_rates[0];
+	if (mac->opmode == NL80211_IFTYPE_ADHOC)
+		ratr_bitmap = 0xfff;
+	ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+			sta->ht_cap.mcs.rx_mask[0] << 12);
 	switch (wirelessmode) {
 	case WIRELESS_MODE_B:
 		ratr_index = RATR_INX_WIRELESS_B;
@@ -2071,6 +2112,7 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
 		break;
 	case WIRELESS_MODE_G:
 		ratr_index = RATR_INX_WIRELESS_GB;
+
 		if (rssi_level == 1)
 			ratr_bitmap &= 0x00000f00;
 		else if (rssi_level == 2)
@@ -2085,7 +2127,8 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
 	case WIRELESS_MODE_N_24G:
 	case WIRELESS_MODE_N_5G:
 		ratr_index = RATR_INX_WIRELESS_NGB;
-		if (mimops == 0) {
+
+		if (mimo_ps == IEEE80211_SMPS_STATIC) {
 			if (rssi_level == 1)
 				ratr_bitmap &= 0x00070000;
 			else if (rssi_level == 2)
@@ -2128,8 +2171,10 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
 				}
 			}
 		}
+
 		if ((curtxbw_40mhz && curshortgi_40mhz) ||
 		    (!curtxbw_40mhz && curshortgi_20mhz)) {
+
 			if (macid == 0)
 				shortgi = true;
 			else if (macid == 1)
@@ -2138,21 +2183,42 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
 		break;
 	default:
 		ratr_index = RATR_INX_WIRELESS_NGB;
+
 		if (rtlphy->rf_type == RF_1T2R)
 			ratr_bitmap &= 0x000ff0ff;
 		else
 			ratr_bitmap &= 0x0f0ff0ff;
 		break;
 	}
-	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "ratr_bitmap :%x\n",
-		 ratr_bitmap);
-	*(u32 *)&rate_mask = ((ratr_bitmap & 0x0fffffff) |
-				      ratr_index << 28);
+	sta_entry->ratr_index = ratr_index;
+
+	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+		 "ratr_bitmap :%x\n", ratr_bitmap);
+	*(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
+				     (ratr_index << 28);
 	rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80;
 	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
 		 "Rate_index:%x, ratr_val:%x, %5phC\n",
 		 ratr_index, ratr_bitmap, rate_mask);
-	rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask);
+	memcpy(rtlpriv->rate_mask, rate_mask, 5);
+	/* rtl92c_fill_h2c_cmd() does USB I/O and will result in a
+	 * "scheduled while atomic" if called directly */
+	schedule_work(&rtlpriv->works.fill_h2c_cmd);
+
+	if (macid != 0)
+		sta_entry->ratr_index = ratr_index;
+}
+
+void rtl92cu_update_hal_rate_tbl(struct ieee80211_hw *hw,
+				 struct ieee80211_sta *sta,
+				 u8 rssi_level)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (rtlpriv->dm.useramask)
+		rtl92cu_update_hal_rate_mask(hw, sta, rssi_level);
+	else
+		rtl92cu_update_hal_rate_table(hw, sta);
 }
 
 void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h
index f41a3aa..8e3ec1e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h
@@ -98,10 +98,6 @@ void rtl92cu_update_interrupt_mask(struct ieee80211_hw *hw,
 				   u32 add_msr, u32 rm_msr);
 void rtl92cu_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
 void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
-void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
-				   struct ieee80211_sta *sta,
-				   u8 rssi_level);
-void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level);
 
 void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw);
 bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
index 85b6bdb..da4f587 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
@@ -289,14 +289,30 @@ void rtl92c_set_key(struct ieee80211_hw *hw, u32 key_index,
 				macaddr = cam_const_broad;
 				entry_id = key_index;
 			} else {
+				if (mac->opmode == NL80211_IFTYPE_AP ||
+				    mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+					entry_id = rtl_cam_get_free_entry(hw,
+								 p_macaddr);
+					if (entry_id >=  TOTAL_CAM_ENTRY) {
+						RT_TRACE(rtlpriv, COMP_SEC,
+							 DBG_EMERG,
+							 "Can not find free hw security cam entry\n");
+						return;
+					}
+				} else {
+					entry_id = CAM_PAIRWISE_KEY_POSITION;
+				}
+
 				key_index = PAIRWISE_KEYIDX;
-				entry_id = CAM_PAIRWISE_KEY_POSITION;
 				is_pairwise = true;
 			}
 		}
 		if (rtlpriv->sec.key_len[key_index] == 0) {
 			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 				 "delete one entry\n");
+			if (mac->opmode == NL80211_IFTYPE_AP ||
+			    mac->opmode == NL80211_IFTYPE_MESH_POINT)
+				rtl_cam_del_entry(hw, p_macaddr);
 			rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
 		} else {
 			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index 938b1e6..826f085 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -106,8 +106,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = {
 	.update_interrupt_mask = rtl92cu_update_interrupt_mask,
 	.get_hw_reg = rtl92cu_get_hw_reg,
 	.set_hw_reg = rtl92cu_set_hw_reg,
-	.update_rate_tbl = rtl92cu_update_hal_rate_table,
-	.update_rate_mask = rtl92cu_update_hal_rate_mask,
+	.update_rate_tbl = rtl92cu_update_hal_rate_tbl,
 	.fill_tx_desc = rtl92cu_tx_fill_desc,
 	.fill_fake_txdesc = rtl92cu_fill_fake_txdesc,
 	.fill_tx_cmddesc = rtl92cu_tx_fill_cmddesc,
@@ -137,6 +136,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = {
 	.phy_lc_calibrate = _rtl92cu_phy_lc_calibrate,
 	.phy_set_bw_mode_callback = rtl92cu_phy_set_bw_mode_callback,
 	.dm_dynamic_txpower = rtl92cu_dm_dynamic_txpower,
+	.fill_h2c_cmd = rtl92c_fill_h2c_cmd,
 };
 
 static struct rtl_mod_params rtl92cu_mod_params = {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.h
index a1310ab..262e1e4 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.h
@@ -49,5 +49,8 @@ bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
 u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw,
 			    enum radio_path rfpath, u32 regaddr, u32 bitmask);
 void rtl92cu_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
+void rtl92cu_update_hal_rate_tbl(struct ieee80211_hw *hw,
+				 struct ieee80211_sta *sta,
+				 u8 rssi_level);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index 76732b0..a3532e0 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -824,6 +824,7 @@ static void rtl_usb_stop(struct ieee80211_hw *hw)
 
 	/* should after adapter start and interrupt enable. */
 	set_hal_stop(rtlhal);
+	cancel_work_sync(&rtlpriv->works.fill_h2c_cmd);
 	/* Enable software */
 	SET_USB_STOP(rtlusb);
 	rtl_usb_deinit(hw);
@@ -1026,6 +1027,16 @@ static bool rtl_usb_tx_chk_waitq_insert(struct ieee80211_hw *hw,
 	return false;
 }
 
+static void rtl_fill_h2c_cmd_work_callback(struct work_struct *work)
+{
+	struct rtl_works *rtlworks =
+	    container_of(work, struct rtl_works, fill_h2c_cmd);
+	struct ieee80211_hw *hw = rtlworks->hw;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtlpriv->cfg->ops->fill_h2c_cmd(hw, H2C_RA_MASK, 5, rtlpriv->rate_mask);
+}
+
 static struct rtl_intf_ops rtl_usb_ops = {
 	.adapter_start = rtl_usb_start,
 	.adapter_stop = rtl_usb_stop,
@@ -1057,6 +1068,8 @@ int rtl_usb_probe(struct usb_interface *intf,
 
 	/* this spin lock must be initialized early */
 	spin_lock_init(&rtlpriv->locks.usb_lock);
+	INIT_WORK(&rtlpriv->works.fill_h2c_cmd,
+		  rtl_fill_h2c_cmd_work_callback);
 
 	rtlpriv->usb_data_index = 0;
 	init_completion(&rtlpriv->firmware_loading_complete);
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 44328ba..cc03e7c 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -1736,6 +1736,8 @@ struct rtl_hal_ops {
 	void (*bt_wifi_media_status_notify) (struct ieee80211_hw *hw,
 					     bool mstate);
 	void (*bt_coex_off_before_lps) (struct ieee80211_hw *hw);
+	void (*fill_h2c_cmd) (struct ieee80211_hw *hw, u8 element_id,
+			      u32 cmd_len, u8 *p_cmdbuffer);
 };
 
 struct rtl_intf_ops {
@@ -1869,6 +1871,7 @@ struct rtl_works {
 	struct delayed_work fwevt_wq;
 
 	struct work_struct lps_change_work;
+	struct work_struct fill_h2c_cmd;
 };
 
 struct rtl_debug {
@@ -2048,6 +2051,7 @@ struct rtl_priv {
 		};
 	};
 	bool enter_ps;	/* true when entering PS */
+	u8 rate_mask[5];
 
 	/*This must be the last item so
 	   that it points to the data allocated
diff --git a/drivers/net/wireless/ti/wl12xx/scan.c b/drivers/net/wireless/ti/wl12xx/scan.c
index affdb3e..4a0bbb1 100644
--- a/drivers/net/wireless/ti/wl12xx/scan.c
+++ b/drivers/net/wireless/ti/wl12xx/scan.c
@@ -310,7 +310,7 @@ static void wl12xx_adjust_channels(struct wl1271_cmd_sched_scan_config *cmd,
 	memcpy(cmd->channels_2, cmd_channels->channels_2,
 	       sizeof(cmd->channels_2));
 	memcpy(cmd->channels_5, cmd_channels->channels_5,
-	       sizeof(cmd->channels_2));
+	       sizeof(cmd->channels_5));
 	/* channels_4 are not supported, so no need to copy them */
 }
 
diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h
index 222d035..9e5484a 100644
--- a/drivers/net/wireless/ti/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h
@@ -36,12 +36,12 @@
 #define WL127X_IFTYPE_SR_VER	3
 #define WL127X_MAJOR_SR_VER	10
 #define WL127X_SUBTYPE_SR_VER	WLCORE_FW_VER_IGNORE
-#define WL127X_MINOR_SR_VER	115
+#define WL127X_MINOR_SR_VER	133
 /* minimum multi-role FW version for wl127x */
 #define WL127X_IFTYPE_MR_VER	5
 #define WL127X_MAJOR_MR_VER	7
 #define WL127X_SUBTYPE_MR_VER	WLCORE_FW_VER_IGNORE
-#define WL127X_MINOR_MR_VER	115
+#define WL127X_MINOR_MR_VER	42
 
 /* FW chip version for wl128x */
 #define WL128X_CHIP_VER		7
@@ -49,7 +49,7 @@
 #define WL128X_IFTYPE_SR_VER	3
 #define WL128X_MAJOR_SR_VER	10
 #define WL128X_SUBTYPE_SR_VER	WLCORE_FW_VER_IGNORE
-#define WL128X_MINOR_SR_VER	115
+#define WL128X_MINOR_SR_VER	133
 /* minimum multi-role FW version for wl128x */
 #define WL128X_IFTYPE_MR_VER	5
 #define WL128X_MAJOR_MR_VER	7
diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c
index 09d9445..2b642f8 100644
--- a/drivers/net/wireless/ti/wl18xx/scan.c
+++ b/drivers/net/wireless/ti/wl18xx/scan.c
@@ -34,7 +34,7 @@ static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd,
 	memcpy(cmd->channels_2, cmd_channels->channels_2,
 	       sizeof(cmd->channels_2));
 	memcpy(cmd->channels_5, cmd_channels->channels_5,
-	       sizeof(cmd->channels_2));
+	       sizeof(cmd->channels_5));
 	/* channels_4 are not supported, so no need to copy them */
 }
 
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 35a57cd..7cb6d36 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1117,6 +1117,7 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event);
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
 int mgmt_index_added(struct hci_dev *hdev);
 int mgmt_index_removed(struct hci_dev *hdev);
+int mgmt_set_powered_failed(struct hci_dev *hdev, int err);
 int mgmt_powered(struct hci_dev *hdev, u8 powered);
 int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable);
 int mgmt_connectable(struct hci_dev *hdev, u8 connectable);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 22980a7..9944c3e 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -42,6 +42,7 @@
 #define MGMT_STATUS_NOT_POWERED		0x0f
 #define MGMT_STATUS_CANCELLED		0x10
 #define MGMT_STATUS_INVALID_INDEX	0x11
+#define MGMT_STATUS_RFKILLED		0x12
 
 struct mgmt_hdr {
 	__le16	opcode;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 33843c5..d817c93 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1555,11 +1555,15 @@ static const struct rfkill_ops hci_rfkill_ops = {
 static void hci_power_on(struct work_struct *work)
 {
 	struct hci_dev *hdev = container_of(work, struct hci_dev, power_on);
+	int err;
 
 	BT_DBG("%s", hdev->name);
 
-	if (hci_dev_open(hdev->id) < 0)
+	err = hci_dev_open(hdev->id);
+	if (err < 0) {
+		mgmt_set_powered_failed(hdev, err);
 		return;
+	}
 
 	if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
 		queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index a76d1ac..24bee07 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3677,10 +3677,14 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
 }
 
 static inline int l2cap_command_rej(struct l2cap_conn *conn,
-				    struct l2cap_cmd_hdr *cmd, u8 *data)
+				    struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+				    u8 *data)
 {
 	struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
 
+	if (cmd_len < sizeof(*rej))
+		return -EPROTO;
+
 	if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
 		return 0;
 
@@ -3829,11 +3833,14 @@ sendresp:
 }
 
 static int l2cap_connect_req(struct l2cap_conn *conn,
-			     struct l2cap_cmd_hdr *cmd, u8 *data)
+			     struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
 {
 	struct hci_dev *hdev = conn->hcon->hdev;
 	struct hci_conn *hcon = conn->hcon;
 
+	if (cmd_len < sizeof(struct l2cap_conn_req))
+		return -EPROTO;
+
 	hci_dev_lock(hdev);
 	if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
 	    !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &hcon->flags))
@@ -3847,7 +3854,8 @@ static int l2cap_connect_req(struct l2cap_conn *conn,
 }
 
 static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
-				    struct l2cap_cmd_hdr *cmd, u8 *data)
+				    struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+				    u8 *data)
 {
 	struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
 	u16 scid, dcid, result, status;
@@ -3855,6 +3863,9 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 	u8 req[128];
 	int err;
 
+	if (cmd_len < sizeof(*rsp))
+		return -EPROTO;
+
 	scid   = __le16_to_cpu(rsp->scid);
 	dcid   = __le16_to_cpu(rsp->dcid);
 	result = __le16_to_cpu(rsp->result);
@@ -3952,6 +3963,9 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
 	struct l2cap_chan *chan;
 	int len, err = 0;
 
+	if (cmd_len < sizeof(*req))
+		return -EPROTO;
+
 	dcid  = __le16_to_cpu(req->dcid);
 	flags = __le16_to_cpu(req->flags);
 
@@ -3975,7 +3989,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
 
 	/* Reject if config buffer is too small. */
 	len = cmd_len - sizeof(*req);
-	if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
+	if (chan->conf_len + len > sizeof(chan->conf_req)) {
 		l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
 			       l2cap_build_conf_rsp(chan, rsp,
 			       L2CAP_CONF_REJECT, flags), rsp);
@@ -4053,14 +4067,18 @@ unlock:
 }
 
 static inline int l2cap_config_rsp(struct l2cap_conn *conn,
-				   struct l2cap_cmd_hdr *cmd, u8 *data)
+				   struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+				   u8 *data)
 {
 	struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
 	u16 scid, flags, result;
 	struct l2cap_chan *chan;
-	int len = le16_to_cpu(cmd->len) - sizeof(*rsp);
+	int len = cmd_len - sizeof(*rsp);
 	int err = 0;
 
+	if (cmd_len < sizeof(*rsp))
+		return -EPROTO;
+
 	scid   = __le16_to_cpu(rsp->scid);
 	flags  = __le16_to_cpu(rsp->flags);
 	result = __le16_to_cpu(rsp->result);
@@ -4161,7 +4179,8 @@ done:
 }
 
 static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
-				       struct l2cap_cmd_hdr *cmd, u8 *data)
+				       struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+				       u8 *data)
 {
 	struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
 	struct l2cap_disconn_rsp rsp;
@@ -4169,6 +4188,9 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
 	struct l2cap_chan *chan;
 	struct sock *sk;
 
+	if (cmd_len != sizeof(*req))
+		return -EPROTO;
+
 	scid = __le16_to_cpu(req->scid);
 	dcid = __le16_to_cpu(req->dcid);
 
@@ -4208,12 +4230,16 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
 }
 
 static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
-				       struct l2cap_cmd_hdr *cmd, u8 *data)
+				       struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+				       u8 *data)
 {
 	struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
 	u16 dcid, scid;
 	struct l2cap_chan *chan;
 
+	if (cmd_len != sizeof(*rsp))
+		return -EPROTO;
+
 	scid = __le16_to_cpu(rsp->scid);
 	dcid = __le16_to_cpu(rsp->dcid);
 
@@ -4243,11 +4269,15 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
 }
 
 static inline int l2cap_information_req(struct l2cap_conn *conn,
-					struct l2cap_cmd_hdr *cmd, u8 *data)
+					struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+					u8 *data)
 {
 	struct l2cap_info_req *req = (struct l2cap_info_req *) data;
 	u16 type;
 
+	if (cmd_len != sizeof(*req))
+		return -EPROTO;
+
 	type = __le16_to_cpu(req->type);
 
 	BT_DBG("type 0x%4.4x", type);
@@ -4294,11 +4324,15 @@ static inline int l2cap_information_req(struct l2cap_conn *conn,
 }
 
 static inline int l2cap_information_rsp(struct l2cap_conn *conn,
-					struct l2cap_cmd_hdr *cmd, u8 *data)
+					struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+					u8 *data)
 {
 	struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
 	u16 type, result;
 
+	if (cmd_len != sizeof(*rsp))
+		return -EPROTO;
+
 	type   = __le16_to_cpu(rsp->type);
 	result = __le16_to_cpu(rsp->result);
 
@@ -5164,16 +5198,16 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
 
 	switch (cmd->code) {
 	case L2CAP_COMMAND_REJ:
-		l2cap_command_rej(conn, cmd, data);
+		l2cap_command_rej(conn, cmd, cmd_len, data);
 		break;
 
 	case L2CAP_CONN_REQ:
-		err = l2cap_connect_req(conn, cmd, data);
+		err = l2cap_connect_req(conn, cmd, cmd_len, data);
 		break;
 
 	case L2CAP_CONN_RSP:
 	case L2CAP_CREATE_CHAN_RSP:
-		err = l2cap_connect_create_rsp(conn, cmd, data);
+		err = l2cap_connect_create_rsp(conn, cmd, cmd_len, data);
 		break;
 
 	case L2CAP_CONF_REQ:
@@ -5181,15 +5215,15 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
 		break;
 
 	case L2CAP_CONF_RSP:
-		err = l2cap_config_rsp(conn, cmd, data);
+		err = l2cap_config_rsp(conn, cmd, cmd_len, data);
 		break;
 
 	case L2CAP_DISCONN_REQ:
-		err = l2cap_disconnect_req(conn, cmd, data);
+		err = l2cap_disconnect_req(conn, cmd, cmd_len, data);
 		break;
 
 	case L2CAP_DISCONN_RSP:
-		err = l2cap_disconnect_rsp(conn, cmd, data);
+		err = l2cap_disconnect_rsp(conn, cmd, cmd_len, data);
 		break;
 
 	case L2CAP_ECHO_REQ:
@@ -5200,11 +5234,11 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
 		break;
 
 	case L2CAP_INFO_REQ:
-		err = l2cap_information_req(conn, cmd, data);
+		err = l2cap_information_req(conn, cmd, cmd_len, data);
 		break;
 
 	case L2CAP_INFO_RSP:
-		err = l2cap_information_rsp(conn, cmd, data);
+		err = l2cap_information_rsp(conn, cmd, cmd_len, data);
 		break;
 
 	case L2CAP_CREATE_CHAN_REQ:
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 35fef22..f8ecbc7 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2700,7 +2700,7 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
 		break;
 
 	case DISCOV_TYPE_LE:
-		if (!lmp_host_le_capable(hdev)) {
+		if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
 			err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
 					 MGMT_STATUS_NOT_SUPPORTED);
 			mgmt_pending_remove(cmd);
@@ -3418,6 +3418,27 @@ new_settings:
 	return err;
 }
 
+int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
+{
+	struct pending_cmd *cmd;
+	u8 status;
+
+	cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
+	if (!cmd)
+		return -ENOENT;
+
+	if (err == -ERFKILL)
+		status = MGMT_STATUS_RFKILLED;
+	else
+		status = MGMT_STATUS_FAILED;
+
+	err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
+
+	mgmt_pending_remove(cmd);
+
+	return err;
+}
+
 int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
 {
 	struct cmd_lookup match = { NULL, hdev };
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index b2296d3..b5562ab 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -770,7 +770,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
 
 	BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
 
-	if (!lmp_host_le_capable(hcon->hdev))
+	if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags))
 		return 1;
 
 	if (sec_level == BT_SECURITY_LOW)
@@ -851,7 +851,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
 	__u8 reason;
 	int err = 0;
 
-	if (!lmp_host_le_capable(conn->hcon->hdev)) {
+	if (!test_bit(HCI_LE_ENABLED, &conn->hcon->hdev->dev_flags)) {
 		err = -ENOTSUPP;
 		reason = SMP_PAIRING_NOTSUPP;
 		goto done;

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

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

^ permalink raw reply related


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