Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: scheduled scan interval
From: Arend Van Spriel @ 2016-11-22  9:10 UTC (permalink / raw)
  To: Luca Coelho, Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1479794340.2517.34.camel@coelho.fi>

On 22-11-2016 6:59, Luca Coelho wrote:
> Hi Arend,
> On Mon, 2016-11-21 at 20:34 +0100, Arend Van Spriel wrote:
>> On 21-11-2016 16:08, Luca Coelho wrote:
>>> Hi Arend,
>>>
>>> On Mon, 2016-11-21 at 13:03 +0100, Arend Van Spriel wrote:
>>>> On 21-11-2016 12:30, Arend Van Spriel wrote:
>>>>> On 21-11-2016 12:19, Arend Van Spriel wrote:
>>>>>> Hi Johannes, Luca,
>>>>>>
>>>>>> The gscan work made me look at scheduled scan and the implementation of
>>>>>> it in brcmfmac. The driver ignored the interval parameter from
>>>>>> user-space. Now I am fixing that. One thing is that our firmware has a
>>>>>> minimum interval which can not be indicated in struct wiphy. The other
>>>>>> issue is how the maximum interval is used in the nl80211.c.
>>>>>>
>>>>>> In nl80211_parse_sched_scan_plans() it is used against value passed in
>>>>>> NL80211_ATTR_SCHED_SCAN_INTERVAL and NL80211_SCHED_SCAN_PLAN_INTERVAL.
>>>>>> For the first one it caps the value to the maximum, but for the second
>>>>>> one it returns -EINVAL. I suspect this is done because maximum interval
>>>>>> was introduced with schedule scan plans, but it feels inconsistent.
>>>>>
>>>>> It also maybe simply wrong to cap. At least brcmfmac does not set the
>>>>> maximum so it will always get interval being zero. Maybe better to do:
>>>>>
>>>>> 		if (wiphy->max_sched_scan_plan_interval &&
>>>>> 		    request->scan_plans[0].interval >
>>>>> 		    wiphy->max_sched_scan_plan_interval)
>>>>> 			return -EINVAL;
>>>>>
>>>>>> Thoughts?
>>>>
>>>> Digging deeper. Looking at v4.3 before introduction of sched_scan_plans.
>>>> struct sched_scan_request::interval was specified in milliseconds! Below
>>>> the drivers that I see having scheduled scan support:
>>>>
>>>> iwlmvm: cap interval, convert to seconds.
>>>> ath6kl: cap to 1sec minimum, no max check, convert to seconds.
>>>> wl12xx: no checking in driver, fw need milliseconds.
>>>> wl18xx: no checking in driver, fw need milliseconds.
>>>>
>>>> The milliseconds conversion seems to be taken care of by multiplying
>>>> with MSEC_PER_SEC in wl{12,18}xx drivers.
>>>>
>>>> It seems in 4.8 only iwlmvm set wiphy->max_sched_scan_plan_interval so
>>>> other drivers will get interval of zero which only ath6kl handles.
>>>
>>> With the introduction of scheduled scan plans, we sort of deprecated
>>> the "generic" scheduled scan interval.  It doesn't make sense to have
>>> both passed at the same time, so nl80211 forbids
>>> NL80211_ATTR_SCHED_SCAN_INTERVAL if we pass
>>> NL80211_ATTR_SCHED_SCAN_PLANS.
>>
>> Indeed, but if no plans are passed it is still allowed.
> 
> That's right.  But the driver will get it as a single plan.
> 
> 
>>> The original NL80211_ATTR_SCHED_SCAN_INTERVAL was specified in msecs,
>>> which is silly because we can never get millisecond accuracy in this. 
>>> Thus, in the plans API, we decided to use seconds instead (because it
>>> makes much more sense).  Additionally, the interval is considered
>>> "advisory", because the FW may not be able guarantee the exact
>>> intervals (for instance, the iwlwifi driver actually starts the
>>> interval timer after scan completion, so if you specify 10 seconds
>>> intervals, in practice they'll be 13-14 seconds).
>>
>> Agree. Our firmware wants to have it in seconds as well.
> 
> It was actually my mistake when I implemented it in my TI days (can't
> hide from git blame ;)). TI's firmware used msecs and I just blindly
> followed it.
> 
> 
>>> I'm not sure I'm answering your question, because I'm also not sure I
>>> understood the question. :)
>>
>> The question is this: Why is the interval capped at
>> max_sched_scan_plan_interval if it exceeds it and no plans are provided
>> (so continue to setup the scheduled scan request) whereas when plans are
>> provided and an interval exceeds max_sched_scan_plan_interval it aborts
>> with -EINVAL.
> 
> Oh, I see.  The problem is that the "max_sched_scan_plan_interval" was
> introduced later.  If the userspace passes
> NL80211__ATTR_SCHED_SCAN_INTERVAL, it probably means that it doesn't
> know about NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL (i.e. it's only using an
> old API).  If it is also, for some reason, passing a very large number,
> we shouldn't suddenly make it fail with -EINVALID, because that would
> be a break of UABI.  And since we know the driver cannot support such a
> large number, we cap it because it's the best we can do.
> 
> Now, if the userspace uses NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL, it
> means that it knows the new API (and was written after the new API was
> introduced), so we can be stricter and assume it must have checked
> NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL.
> 
> Makes sense?

Not really. As you say if user-space passes
NL80211_ATTR_SCHED_SCAN_INTERVAL it is using old API. Otherwise it
should pass NL80211_ATTR_SCHED_SCAN_PLANS.

>> And a follow-up question for this snippet of code in
>> nl80211_parse_sched_scan_plans():
>>
>> 	if (!attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
>> 		u32 interval;
>>
>> 		/*
>> 		 * If scan plans are not specified,
>> 		 * %NL80211_ATTR_SCHED_SCAN_INTERVAL must be specified. In this
>> 		 * case one scan plan will be set with the specified scan
>> 		 * interval and infinite number of iterations.
>> 		 */
>> 		if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
>> 			return -EINVAL;
>>
>> 		interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
>> 		if (!interval)
>> 			return -EINVAL;
>>
>> 		request->scan_plans[0].interval =
>> 			DIV_ROUND_UP(interval, MSEC_PER_SEC);
>> 		if (!request->scan_plans[0].interval)
>> 			return -EINVAL;
>>
>> 		if (request->scan_plans[0].interval >
>> 		    wiphy->max_sched_scan_plan_interval)
>> 			request->scan_plans[0].interval =
>> 				wiphy->max_sched_scan_plan_interval;
>>
>> 		return 0;
>> 	}
>>
>> So in v4.3 the interval was only validated to be non-zero. Now the
>> interval is validated and capped to wiphy->max_sched_scan_plan_interval
>> but apart from iwlmvm there are no driver specifying that so
>> max_sched_scan_plan_interval = 0 for those and interval is unsigned int
>> not equal to zero. So the last if statement above is true setting the
>> interval to zero. I think the if statement should be extended to assure
>> max_sched_scan_interval is non-zero, ie. set explicitly by the driver:
>>
>> 		if (wiphy->max_sched_scan_plan_interval &&
>> 		    request->scan_plans[0].interval >
>> 		    wiphy->max_sched_scan_plan_interval)
>> 			request->scan_plans[0].interval =
>> 				wiphy->max_sched_scan_plan_interval;
> 
> If the driver doesn't set the max_sched_scan_plan_interval, mac80211's
> default of MAX_U32 will be used:
> 
> struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
> 			   const char *requested_name)
> {
> [...]
> 	rdev->wiphy.max_sched_scan_plans = 1;
> 	rdev->wiphy.max_sched_scan_plan_interval = U32_MAX;
> 
> 	return &rdev->wiphy;
> }
> EXPORT_SYMBOL(wiphy_new_nm);
> 
> ...so max_sched_scan_plan_interval will never be zero, unless the
> driver explicitly sets it to zero.

I think you are overlooking the cfg80211-based drivers here. According
to lxr at least brcmfmac, mwifiex, and ath6kl are not specifying it.
"Funny" detail is that scheduled scan support in mwifiex seems to be
introduced after the scan plan API change.

With the old API nl80211 only assured it to be non-zero. The only one
capping the value was iwlmvm. The only one setting the
max_sched_scan_plan_interval (overriding mac80211 value) now is iwlmvm.
So I think checking if it is set before capping it retains the old API
behaviour.

Regards,
Arend

^ permalink raw reply

* Re: scheduled scan interval
From: Luca Coelho @ 2016-11-22  9:19 UTC (permalink / raw)
  To: Arend Van Spriel, Johannes Berg; +Cc: linux-wireless
In-Reply-To: <006ec2b0-9659-49ed-40f7-b8980b7e3ec7@broadcom.com>

On Tue, 2016-11-22 at 10:10 +0100, Arend Van Spriel wrote:
> On 22-11-2016 6:59, Luca Coelho wrote:
> > Oh, I see.  The problem is that the "max_sched_scan_plan_interval" was
> > introduced later.  If the userspace passes
> > NL80211__ATTR_SCHED_SCAN_INTERVAL, it probably means that it doesn't
> > know about NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL (i.e. it's only using an
> > old API).  If it is also, for some reason, passing a very large number,
> > we shouldn't suddenly make it fail with -EINVALID, because that would
> > be a break of UABI.  And since we know the driver cannot support such a
> > large number, we cap it because it's the best we can do.
> > 
> > Now, if the userspace uses NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL, it
> > means that it knows the new API (and was written after the new API was
> > introduced), so we can be stricter and assume it must have checked
> > NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL.
> > 
> > Makes sense?
> 
> Not really. As you say if user-space passes
> NL80211_ATTR_SCHED_SCAN_INTERVAL it is using old API. Otherwise it
> should pass NL80211_ATTR_SCHED_SCAN_PLANS.

Errr... I meant "if the userspace uses NL80211_ATTR_SCHED_SCAN_PLANS",
pasted the wrong thing. ;)


> If the driver doesn't set the max_sched_scan_plan_interval, mac80211's
> > default of MAX_U32 will be used:
> > 
> > struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
> > 			   const char *requested_name)
> > {
> > [...]
> > 	rdev->wiphy.max_sched_scan_plans = 1;
> > 	rdev->wiphy.max_sched_scan_plan_interval = U32_MAX;
> > 
> > 	return &rdev->wiphy;
> > }
> > EXPORT_SYMBOL(wiphy_new_nm);
> > 
> > ...so max_sched_scan_plan_interval will never be zero, unless the
> > driver explicitly sets it to zero.
> 
> I think you are overlooking the cfg80211-based drivers here. According
> to lxr at least brcmfmac, mwifiex, and ath6kl are not specifying it.
> "Funny" detail is that scheduled scan support in mwifiex seems to be
> introduced after the scan plan API change.

You're right, I did overlook non-mac80211 drivers.


> With the old API nl80211 only assured it to be non-zero. The only one
> capping the value was iwlmvm. The only one setting the
> max_sched_scan_plan_interval (overriding mac80211 value) now is iwlmvm.
> So I think checking if it is set before capping it retains the old API
> behaviour.

Fair enough.  The change you propose, to also check whether the value
is set (since 0 interval doesn't make sense), is valid.  :)

--
Luca.

^ permalink raw reply

* Re: scheduled scan interval
From: Arend Van Spriel @ 2016-11-22  9:30 UTC (permalink / raw)
  To: Luca Coelho, Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1479806342.2517.44.camel@coelho.fi>

On 22-11-2016 10:19, Luca Coelho wrote:
> On Tue, 2016-11-22 at 10:10 +0100, Arend Van Spriel wrote:
>> On 22-11-2016 6:59, Luca Coelho wrote:
>>> Oh, I see.  The problem is that the "max_sched_scan_plan_interval" was
>>> introduced later.  If the userspace passes
>>> NL80211__ATTR_SCHED_SCAN_INTERVAL, it probably means that it doesn't
>>> know about NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL (i.e. it's only using an
>>> old API).  If it is also, for some reason, passing a very large number,
>>> we shouldn't suddenly make it fail with -EINVALID, because that would
>>> be a break of UABI.  And since we know the driver cannot support such a
>>> large number, we cap it because it's the best we can do.
>>>
>>> Now, if the userspace uses NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL, it
>>> means that it knows the new API (and was written after the new API was
>>> introduced), so we can be stricter and assume it must have checked
>>> NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL.
>>>
>>> Makes sense?
>>
>> Not really. As you say if user-space passes
>> NL80211_ATTR_SCHED_SCAN_INTERVAL it is using old API. Otherwise it
>> should pass NL80211_ATTR_SCHED_SCAN_PLANS.
> 
> Errr... I meant "if the userspace uses NL80211_ATTR_SCHED_SCAN_PLANS",
> pasted the wrong thing. ;)
> 
> 
>> If the driver doesn't set the max_sched_scan_plan_interval, mac80211's
>>> default of MAX_U32 will be used:
>>>
>>> struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
>>> 			   const char *requested_name)
>>> {
>>> [...]
>>> 	rdev->wiphy.max_sched_scan_plans = 1;
>>> 	rdev->wiphy.max_sched_scan_plan_interval = U32_MAX;
>>>
>>> 	return &rdev->wiphy;
>>> }
>>> EXPORT_SYMBOL(wiphy_new_nm);
>>>
>>> ...so max_sched_scan_plan_interval will never be zero, unless the
>>> driver explicitly sets it to zero.
>>
>> I think you are overlooking the cfg80211-based drivers here. According
>> to lxr at least brcmfmac, mwifiex, and ath6kl are not specifying it.
>> "Funny" detail is that scheduled scan support in mwifiex seems to be
>> introduced after the scan plan API change.
> 
> You're right, I did overlook non-mac80211 drivers.
> 
> 
>> With the old API nl80211 only assured it to be non-zero. The only one
>> capping the value was iwlmvm. The only one setting the
>> max_sched_scan_plan_interval (overriding mac80211 value) now is iwlmvm.
>> So I think checking if it is set before capping it retains the old API
>> behaviour.
> 
> Fair enough.  The change you propose, to also check whether the value
> is set (since 0 interval doesn't make sense), is valid.  :)

Thanks. Patch coming up.

Gr. AvS

^ permalink raw reply

* Re: ath10k stuck in mesh mode
From: Matteo Grandi @ 2016-11-22  9:43 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Bob Copeland, LinuxWireless Mailing List
In-Reply-To: <CAHdg3xYFWiC1YegR8U9WJ52zjYK242eYWHvx8rsuY6RZvD+9og@mail.gmail.com>

Dear Bob, Michal, all

I've finally managed to have a 80MHz channel bandwidth, thanks to your hint!
The problem was related to the CRDA that even if it looks correctly
installed, it actually doesn't work as supposed.
I downloaded and recompiled the CRDA-3.18
(http://drvbp1.linux-foundation.org/~mcgrof/rel-html/crda/) and set-up
the regulatory domain.
Notice that without setting up the reg. domain all the available
channels have the "passive scanning" label because the CRDA prevent
beaconing so mesh mode is not possible (maybe it's otherwise possible
to operate in STA mode that doesn't require to send frames(?)).

Now I can have a mesh communication using 80MHz channel bandwidth, but
MIMO still doesn't work.
In fact the highest MCS reached was MCS9 that is the highest MCS with
Single Spatial Stream, and I can't managed to have MIMO.
I played with the antennas position and distance, with the
polarization and the presence or not of LOS, but by sniffing the
transmissions I sow only MCS9 even if in the radiotap header field
there are Antenna 0 and Antenna 1.
However the radio information field report "Spatial streams: 1".

Does anyone experienced something similar with the use of MIMO in mesh
mode with the ath10k fw?
I will thank any light you can shed to this!
Thank you very much

Best Regards

Matteo

2016-11-21 13:53 GMT+01:00 Matteo Grandi <iu5bdp@gmail.com>:
> Yes, I noticed it, in fact it seems to be the reg. domain of the ath9k
> (there is also an ath9k card plugged on the same board).
> But it is in contrast with what I found in the syslog:
>
> Nov 21 07:53:23 MrProper kernel: [    9.591563] ath: Regpair used: 0x3a
> Nov 21 07:53:23 MrProper kernel: [    9.591573] cfg80211: Updating
> information on frequency 5180 MHz with regulatory rule:
> Nov 21 07:53:23 MrProper kernel: [    9.591581] cfg80211: (5140000 KHz
> - 5360000 KHz @ 80000 KHz), (N/A, 3000 mBm)
> [...]
> - 5360000 KHz @ 80000 KHz), (N/A, 3000 mBm)
> Nov 21 07:53:23 MrProper kernel: [    9.591654] cfg80211: Updating
> information on frequency 5300 MHz with regulatory rule:
> Nov 21 07:53:23 MrProper kernel: [    9.591661] cfg80211: (5140000 KHz
> - 5360000 KHz @ 80000 KHz), (N/A, 3000 mBm)
> Nov 21 07:53:23 MrProper kernel: [    9.591668] cfg80211: Updating
> information on frequency 5320 MHz with regulatory rule:
> Nov 21 07:53:23 MrProper kernel: [    9.591675] cfg80211: (5140000 KHz
> - 5360000 KHz @ 80000 KHz), (N/A, 3000 mBm
>
> where there are @80MHz frequency slots.
>
> Is it possible that the system, showing all these different reg.
> domains from different cards, chose the most constrained one?
>
> 2016-11-21 11:53 GMT+01:00 Michal Kazior <michal.kazior@tieto.com>:
>> On 21 November 2016 at 10:46, Matteo Grandi <iu5bdp@gmail.com> wrote:
>>> Dear Bob, Michal, all,
>>>
>>> I've just tried your advices (actually I already tried it following
>>> the wireless.wiki.kernel web pages) and I had a look at the syslog
>>> while I was typing the commands
>>> At the beginning I have this
>> [...]
>>> Other (hopefully) useful info:
>>> root@MrProper:~# iw reg get
>>> global
>>> country US: DFS-UNSET
>>>     (2402 - 2472 @ 40), (3, 27), (N/A)
>>>     (5170 - 5250 @ 40), (3, 17), (N/A)
>>>     (5250 - 5330 @ 40), (3, 20), (0 ms), DFS
>>>     (5490 - 5600 @ 40), (3, 20), (0 ms), DFS
>>>     (5650 - 5710 @ 40), (3, 20), (0 ms), DFS
>>>     (5735 - 5835 @ 40), (3, 30), (N/A)
>>>     (57240 - 63720 @ 2160), (N/A, 40), (N/A)
>>>
>>> phy#2
>>> country US: DFS-UNSET
>>>     (2402 - 2472 @ 40), (3, 27), (N/A)
>>>     (5170 - 5250 @ 40), (3, 17), (N/A)
>>>     (5250 - 5330 @ 40), (3, 20), (0 ms), DFS
>>>     (5490 - 5600 @ 40), (3, 20), (0 ms), DFS
>>>     (5650 - 5710 @ 40), (3, 20), (0 ms), DFS
>>>     (5735 - 5835 @ 40), (3, 30), (N/A)
>>>     (57240 - 63720 @ 2160), (N/A, 40), (N/A)
>>>
>>> phy#0
>>> country US: DFS-UNSET
>>>     (2402 - 2472 @ 40), (3, 27), (N/A)
>>>     (5170 - 5250 @ 40), (3, 17), (N/A)
>>>     (5250 - 5330 @ 40), (3, 20), (0 ms), DFS
>>>     (5490 - 5600 @ 40), (3, 20), (0 ms), DFS
>>>     (5650 - 5710 @ 40), (3, 20), (0 ms), DFS
>>>     (5735 - 5835 @ 40), (3, 30), (N/A)
>>>     (57240 - 63720 @ 2160), (N/A, 40), (N/A)
>>>
>>> phy#1
>>> country US: DFS-UNSET
>>>     (2402 - 2472 @ 40), (3, 27), (N/A)
>>>     (5170 - 5250 @ 40), (3, 17), (N/A)
>>>     (5250 - 5330 @ 40), (3, 20), (0 ms), DFS
>>>     (5490 - 5600 @ 40), (3, 20), (0 ms), DFS
>>>     (5650 - 5710 @ 40), (3, 20), (0 ms), DFS
>>>     (5735 - 5835 @ 40), (3, 30), (N/A)
>>>     (57240 - 63720 @ 2160), (N/A, 40), (N/A)
>>>[...]
>>>
>>> Checking on Internet I didn't find a working solution, and the data
>>> rate stucks to 120Mbps MCS7.
>>> For me it still a mistery, I hope in your help.
>>
>> Note the "@ 40" for all frequency ranges (except 60GHz band). Your
>> regulatory database seems to be limiting you to 40 MHz (it's probably
>> very old/ out of date). You'll need to update it to be able to use 80
>> MHz.
>>
>>
>> Michal

^ permalink raw reply

* [PATCH] nl80211: change validation of scheduled scan interval values
From: Arend van Spriel @ 2016-11-22 10:22 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel

When user-space does not provide scheduled scan plans, ie. uses the
old scheduled scan API containing NL80211_ATTR_SCHED_SCAN_INTERVAL.
The interval value passed by user-space is validated against
struct wiphy::max_sched_scan_plan_interval and if it is exceeding
it the interval is set to struct wiphy::max_sched_scan_plan_interval.
However, when the driver does not set this limit the interval the
interval in the request will always be zero. Hence add a check to
see whether the driver set struct wiphy::max_sched_scan_plan_interval.

For the new API, ie. for scheduled scan plans, the interval validation
has been simalarly adjusted to assure the limit is non-zero.

Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
 net/wireless/nl80211.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 24ab199..e621554 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6777,7 +6777,8 @@ static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
 		if (!request->scan_plans[0].interval)
 			return -EINVAL;
 
-		if (request->scan_plans[0].interval >
+		if (wiphy->max_sched_scan_plan_interval &&
+		    request->scan_plans[0].interval >
 		    wiphy->max_sched_scan_plan_interval)
 			request->scan_plans[0].interval =
 				wiphy->max_sched_scan_plan_interval;
@@ -6801,7 +6802,10 @@ static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
 
 		request->scan_plans[i].interval =
 			nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_INTERVAL]);
-		if (!request->scan_plans[i].interval ||
+		if (!request->scan_plans[i].interval)
+			return -EINVAL;
+
+		if (wiphy->max_sched_scan_plan_interval &&
 		    request->scan_plans[i].interval >
 		    wiphy->max_sched_scan_plan_interval)
 			return -EINVAL;
-- 
1.9.1

^ permalink raw reply related

* [PATCH 0/3][RESEND][RFC] CQM RSSI event with many thresholds
From: Andrew Zaborowski @ 2016-11-22 10:29 UTC (permalink / raw)
  To: linux-wireless

From: Andrew Zaborowski <balrogg@gmail.com>

This is a first stab at a nl80211 API using multiple RSSI thresholds
discussed previously.  It is similar to the current CQM RSSI event with
one threshold and a hysteresis parameter.  I tried to avoid creating
new nl80211 commands and events so I extended the existing command.
There's still a NL80211_ATTR_CQM_RSSI_THOLD attribute and a hysteresis
attribute but multiple thresholds can be supplied as an array.

All this is a proposal and open to changes.

There are two different mechanisms for compatibility with the current
behavior in which events are generated every time the RSSI value is
more than $hysteresis dBm away from the last event's level, even if
$threshold wasn't crossed.  For example with the rssi going up from 20dBm
and the threshold set at 40 and hysteresis at 5, there'll be events at
40, 45, 50 and so on.  I assume this is intentional because most
drivers replicate this behavior.  If 2 or more thresholds are supplied
in NL80211_ATTR_CQM_RSSI_THOLD (i.e. it is not 4 byte long) this will
enable the new mechanism and events are only generated when a threshold
is crossed.

My opinion is that the new mechanism is similar enough to the current
one that it would be best if each driver didn't have to implement both
mechanisms, and one could be a special case of the other.  However I
can't update all drivers because I can't test them.  So at the driver
level there have to be two methods until all drivers implement the
new method (set_cqm_rssi_range_config, which uses a low and a high
threshold) and the current behavior can be implemented on to of it.
So the next best thing is that at least the netlink API can present it
as a single interface.  Also both mechanisms never have to be enabled
simultaneously, the driver doesn't have to support them both at the
same time.

Also it seems that the wl1271 (wlcore) driver can offload RSSI
monitoring to hardware using exactly the two parameters used today:
one threshold and a hysteresis value, and no other mechanism is
supported by the hardware, so it wouldn't make sense for it to drop
the current method.

Andrew Zaborowski (3):
  mac80211: Pass new RSSI level in CQM RSSI notification
  cfg80211: Pass new RSSI level in CQM RSSI notification
  nl80211/mac80211: Accept multiple RSSI thresholds for CQM

 drivers/net/wireless/intel/iwlwifi/mvm/rx.c      |   2 +
 drivers/net/wireless/marvell/mwifiex/sta_event.c |   4 +-
 drivers/net/wireless/rndis_wlan.c                |   2 +-
 drivers/net/wireless/rsi/rsi_91x_mac80211.c      |   2 +-
 drivers/net/wireless/st/cw1200/sta.c             |   2 +-
 drivers/net/wireless/ti/wl1251/event.c           |   4 +-
 drivers/net/wireless/ti/wlcore/event.c           |   3 +-
 include/net/cfg80211.h                           |  15 ++-
 include/net/mac80211.h                           |   8 ++
 include/uapi/linux/nl80211.h                     |   7 +-
 net/mac80211/cfg.c                               |  28 +++++
 net/mac80211/mlme.c                              |  33 ++++-
 net/mac80211/trace.h                             |  11 +-
 net/wireless/core.c                              |  13 ++
 net/wireless/core.h                              |   9 ++
 net/wireless/nl80211.c                           | 146 +++++++++++++++++++++--
 net/wireless/rdev-ops.h                          |  12 ++
 net/wireless/trace.h                             |  33 ++++-
 18 files changed, 299 insertions(+), 35 deletions(-)

-- 
2.7.4

^ permalink raw reply

* [PATCH 1/3][RESEND] mac80211: Pass new RSSI level in CQM RSSI notification
From: Andrew Zaborowski @ 2016-11-22 10:29 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <1479810592-2474-1-git-send-email-andrew.zaborowski@intel.com>

---
 drivers/net/wireless/intel/iwlwifi/mvm/rx.c |  2 ++
 drivers/net/wireless/rsi/rsi_91x_mac80211.c |  2 +-
 drivers/net/wireless/st/cw1200/sta.c        |  2 +-
 drivers/net/wireless/ti/wl1251/event.c      |  4 ++--
 drivers/net/wireless/ti/wlcore/event.c      |  3 ++-
 include/net/mac80211.h                      |  2 ++
 net/mac80211/mlme.c                         |  7 ++++---
 net/mac80211/trace.h                        | 11 +++++++----
 8 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
index 0e60e38..e06a2e3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
@@ -571,6 +571,7 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
 		ieee80211_cqm_rssi_notify(
 			vif,
 			NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+			sig,
 			GFP_KERNEL);
 	} else if (sig > thold &&
 		   (last_event == 0 || sig > last_event + hyst)) {
@@ -580,6 +581,7 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
 		ieee80211_cqm_rssi_notify(
 			vif,
 			NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+			sig,
 			GFP_KERNEL);
 	}
 }
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index dbb2389..3e260b4 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -818,7 +818,7 @@ static void rsi_perform_cqm(struct rsi_common *common,
 
 	common->cqm_info.last_cqm_event_rssi = rssi;
 	rsi_dbg(INFO_ZONE, "CQM: Notifying event: %d\n", event);
-	ieee80211_cqm_rssi_notify(adapter->vifs[0], event, GFP_KERNEL);
+	ieee80211_cqm_rssi_notify(adapter->vifs[0], event, rssi, GFP_KERNEL);
 
 	return;
 }
diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c
index daf06a4..a522248 100644
--- a/drivers/net/wireless/st/cw1200/sta.c
+++ b/drivers/net/wireless/st/cw1200/sta.c
@@ -1019,7 +1019,7 @@ void cw1200_event_handler(struct work_struct *work)
 				NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW :
 				NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
 			pr_debug("[CQM] RSSI event: %d.\n", rcpi_rssi);
-			ieee80211_cqm_rssi_notify(priv->vif, cqm_evt,
+			ieee80211_cqm_rssi_notify(priv->vif, cqm_evt, rcpi_rssi,
 						  GFP_KERNEL);
 			break;
 		}
diff --git a/drivers/net/wireless/ti/wl1251/event.c b/drivers/net/wireless/ti/wl1251/event.c
index d0593bc..f5acd24 100644
--- a/drivers/net/wireless/ti/wl1251/event.c
+++ b/drivers/net/wireless/ti/wl1251/event.c
@@ -150,7 +150,7 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
 				     "ROAMING_TRIGGER_LOW_RSSI_EVENT");
 			ieee80211_cqm_rssi_notify(wl->vif,
 				NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
-				GFP_KERNEL);
+				0, GFP_KERNEL);
 		}
 
 		if (vector & ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID) {
@@ -158,7 +158,7 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
 				     "ROAMING_TRIGGER_REGAINED_RSSI_EVENT");
 			ieee80211_cqm_rssi_notify(wl->vif,
 				NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
-				GFP_KERNEL);
+				0, GFP_KERNEL);
 		}
 	}
 
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c
index 4b59f67..f2e90d2 100644
--- a/drivers/net/wireless/ti/wlcore/event.c
+++ b/drivers/net/wireless/ti/wlcore/event.c
@@ -129,7 +129,8 @@ void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr)
 
 		vif = wl12xx_wlvif_to_vif(wlvif);
 		if (event != wlvif->last_rssi_event)
-			ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL);
+			ieee80211_cqm_rssi_notify(vif, event, metric,
+						  GFP_KERNEL);
 		wlvif->last_rssi_event = event;
 	}
 }
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index a810dfc..33026e1 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -5244,6 +5244,7 @@ void ieee80211_resume_disconnect(struct ieee80211_vif *vif);
  *
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @rssi_event: the RSSI trigger event type
+ * @rssi_level: new RSSI level value or 0 if not available
  * @gfp: context flags
  *
  * When the %IEEE80211_VIF_SUPPORTS_CQM_RSSI is set, and a connection quality
@@ -5252,6 +5253,7 @@ void ieee80211_resume_disconnect(struct ieee80211_vif *vif);
  */
 void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
 			       enum nl80211_cqm_rssi_threshold_event rssi_event,
+			       s32 rssi_level,
 			       gfp_t gfp);
 
 /**
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7486f2d..a55cdd7 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3405,14 +3405,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 			ieee80211_cqm_rssi_notify(
 				&sdata->vif,
 				NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
-				GFP_KERNEL);
+				sig, GFP_KERNEL);
 		} else if (sig > thold &&
 			   (last_event == 0 || sig > last_event + hyst)) {
 			ifmgd->last_cqm_event_signal = sig;
 			ieee80211_cqm_rssi_notify(
 				&sdata->vif,
 				NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
-				GFP_KERNEL);
+				sig, GFP_KERNEL);
 		}
 	}
 
@@ -5000,11 +5000,12 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
 
 void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
 			       enum nl80211_cqm_rssi_threshold_event rssi_event,
+			       s32 rssi_level,
 			       gfp_t gfp)
 {
 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 
-	trace_api_cqm_rssi_notify(sdata, rssi_event);
+	trace_api_cqm_rssi_notify(sdata, rssi_event, rssi_level);
 
 	cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
 }
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 92a47af..f78d9f4 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -1996,23 +1996,26 @@ TRACE_EVENT(api_connection_loss,
 
 TRACE_EVENT(api_cqm_rssi_notify,
 	TP_PROTO(struct ieee80211_sub_if_data *sdata,
-		 enum nl80211_cqm_rssi_threshold_event rssi_event),
+		 enum nl80211_cqm_rssi_threshold_event rssi_event,
+		 s32 rssi_level),
 
-	TP_ARGS(sdata, rssi_event),
+	TP_ARGS(sdata, rssi_event, rssi_level),
 
 	TP_STRUCT__entry(
 		VIF_ENTRY
 		__field(u32, rssi_event)
+		__field(s32, rssi_level)
 	),
 
 	TP_fast_assign(
 		VIF_ASSIGN;
 		__entry->rssi_event = rssi_event;
+		__entry->rssi_level = rssi_level;
 	),
 
 	TP_printk(
-		VIF_PR_FMT " event:%d",
-		VIF_PR_ARG, __entry->rssi_event
+		VIF_PR_FMT " event:%d rssi:%d",
+		VIF_PR_ARG, __entry->rssi_event, __entry->rssi_level
 	)
 );
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH 2/3][RESEND] cfg80211: Pass new RSSI level in CQM RSSI notification
From: Andrew Zaborowski @ 2016-11-22 10:29 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <1479810592-2474-1-git-send-email-andrew.zaborowski@intel.com>

Update the drivers to pass the RSSI level as a cfg80211_cqm_rssi_notify
parameter and pass this value to userspace in a new nl80211 attribute.
This helps both userspace and also helps in the implementation of the
multiple RSSI thresholds CQM mechanism.

Note for marvell/mwifiexe I pass 0 for the RSSI value because the new
RSSI value is not available to the driver at the time of the
cfg80211_cqm_rssi_notify call, but the driver queries the new value
immediately after that, so it is actually available just a moment later
if we wanted to defer caling cfg80211_cqm_rssi_notify until that moment.
Without this, the new cfg80211 code (patch 3) will call .get_station
which will send a duplicate HostCmd_CMD_RSSI_INFO command to the hardware.
---
 drivers/net/wireless/marvell/mwifiex/sta_event.c |  4 ++--
 drivers/net/wireless/rndis_wlan.c                |  2 +-
 include/net/cfg80211.h                           |  3 ++-
 include/uapi/linux/nl80211.h                     |  3 +++
 net/mac80211/mlme.c                              |  2 +-
 net/wireless/nl80211.c                           |  9 +++++++--
 net/wireless/trace.h                             | 11 +++++++----
 7 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c
index 9df0c4d..5cc3aa7 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_event.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c
@@ -824,7 +824,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 	case EVENT_RSSI_LOW:
 		cfg80211_cqm_rssi_notify(priv->netdev,
 					 NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
-					 GFP_KERNEL);
+					 0, GFP_KERNEL);
 		mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
 				 HostCmd_ACT_GEN_GET, 0, NULL, false);
 		priv->subsc_evt_rssi_state = RSSI_LOW_RECVD;
@@ -839,7 +839,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 	case EVENT_RSSI_HIGH:
 		cfg80211_cqm_rssi_notify(priv->netdev,
 					 NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
-					 GFP_KERNEL);
+					 0, GFP_KERNEL);
 		mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
 				 HostCmd_ACT_GEN_GET, 0, NULL, false);
 		priv->subsc_evt_rssi_state = RSSI_HIGH_RECVD;
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 603c904..785334f 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -3187,7 +3187,7 @@ static void rndis_do_cqm(struct usbnet *usbdev, s32 rssi)
 		return;
 
 	priv->last_cqm_event_rssi = rssi;
-	cfg80211_cqm_rssi_notify(usbdev->net, event, GFP_KERNEL);
+	cfg80211_cqm_rssi_notify(usbdev->net, event, rssi, GFP_KERNEL);
 }
 
 #define DEVICE_POLLER_JIFFIES (HZ)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index bd19faa..632dce1 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5167,6 +5167,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
  * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event
  * @dev: network device
  * @rssi_event: the triggered RSSI event
+ * @rssi_level: new RSSI level value or 0 if not available
  * @gfp: context flags
  *
  * This function is called when a configured connection quality monitoring
@@ -5174,7 +5175,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
  */
 void cfg80211_cqm_rssi_notify(struct net_device *dev,
 			      enum nl80211_cqm_rssi_threshold_event rssi_event,
-			      gfp_t gfp);
+			      s32 rssi_level, gfp_t gfp);
 
 /**
  * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 56368e9..48108fd 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3859,6 +3859,8 @@ enum nl80211_ps_state {
  *	%NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting.
  * @NL80211_ATTR_CQM_BEACON_LOSS_EVENT: flag attribute that's set in a beacon
  *	loss event
+ * @NL80211_ATTR_CQM_RSSI_LEVEL: the RSSI value in dBm that triggered the
+ *	RSSI threshold event.
  * @__NL80211_ATTR_CQM_AFTER_LAST: internal
  * @NL80211_ATTR_CQM_MAX: highest key attribute
  */
@@ -3872,6 +3874,7 @@ enum nl80211_attr_cqm {
 	NL80211_ATTR_CQM_TXE_PKTS,
 	NL80211_ATTR_CQM_TXE_INTVL,
 	NL80211_ATTR_CQM_BEACON_LOSS_EVENT,
+	NL80211_ATTR_CQM_RSSI_LEVEL,
 
 	/* keep last */
 	__NL80211_ATTR_CQM_AFTER_LAST,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index a55cdd7..6898ecb 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -5007,7 +5007,7 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
 
 	trace_api_cqm_rssi_notify(sdata, rssi_event, rssi_level);
 
-	cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
+	cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, rssi_level, gfp);
 }
 EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c510810..5d10774 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -9278,6 +9278,7 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
 	[NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
 	[NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
 	[NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
+	[NL80211_ATTR_CQM_RSSI_LEVEL] = { .type = NLA_S32 },
 };
 
 static int nl80211_set_cqm_txe(struct genl_info *info,
@@ -13737,11 +13738,11 @@ static void cfg80211_send_cqm(struct sk_buff *msg, gfp_t gfp)
 
 void cfg80211_cqm_rssi_notify(struct net_device *dev,
 			      enum nl80211_cqm_rssi_threshold_event rssi_event,
-			      gfp_t gfp)
+			      s32 rssi_level, gfp_t gfp)
 {
 	struct sk_buff *msg;
 
-	trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
+	trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
 
 	if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
 		    rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
@@ -13755,6 +13756,10 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 			rssi_event))
 		goto nla_put_failure;
 
+	if (rssi_level && nla_put_s32(msg, NL80211_ATTR_CQM_RSSI_LEVEL,
+				      rssi_level))
+		goto nla_put_failure;
+
 	cfg80211_send_cqm(msg, gfp);
 
 	return;
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index a3d0a91..6ac46a0 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2472,18 +2472,21 @@ TRACE_EVENT(cfg80211_mgmt_tx_status,
 
 TRACE_EVENT(cfg80211_cqm_rssi_notify,
 	TP_PROTO(struct net_device *netdev,
-		 enum nl80211_cqm_rssi_threshold_event rssi_event),
-	TP_ARGS(netdev, rssi_event),
+		 enum nl80211_cqm_rssi_threshold_event rssi_event,
+		 s32 rssi_level),
+	TP_ARGS(netdev, rssi_event, rssi_level),
 	TP_STRUCT__entry(
 		NETDEV_ENTRY
 		__field(enum nl80211_cqm_rssi_threshold_event, rssi_event)
+		__field(s32, rssi_level)
 	),
 	TP_fast_assign(
 		NETDEV_ASSIGN;
 		__entry->rssi_event = rssi_event;
+		__entry->rssi_level = rssi_level;
 	),
-	TP_printk(NETDEV_PR_FMT ", rssi event: %d",
-		  NETDEV_PR_ARG, __entry->rssi_event)
+	TP_printk(NETDEV_PR_FMT ", rssi event: %d, level: %d",
+		  NETDEV_PR_ARG, __entry->rssi_event, __entry->rssi_level)
 );
 
 TRACE_EVENT(cfg80211_reg_can_beacon,
-- 
2.7.4

^ permalink raw reply related

* [PATCH 3/3][RESEND][RFC] nl80211/mac80211: Accept multiple RSSI thresholds for CQM
From: Andrew Zaborowski @ 2016-11-22 10:29 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <1479810592-2474-1-git-send-email-andrew.zaborowski@intel.com>

Change the SET CQM command RSSI threshold attribute semantic to accept
any number of thresholds as a sorted array.  The API should be backwards
compatible so that if one s32 threshold value is passed, the old
mechanism is enabled.  The netlink event generated is the same too.

cfg80211 handles an arbitrary number of RSSI thresholds but drivers have
to provide a method (set_cqm_rssi_range_config) that configures a range
set by a high and a low value.  Drivers have to call back when the RSSI
goes out of that range and there's no additional event every time the
range is reconfigured.  There's no reason that the whole mechanism with
more than 2 thresholds couldn't be offloaded if the was hardware
available.

I added only a mac80211 implementation of the set_cqm_rssi_range_config
method as an illustration and because I can't run-time test any other
driver.  In this patch there's also no API for mac80211-based drivers
that do beacon filtering to offload this but that would be the intended
use.
---
 include/net/cfg80211.h       |  12 ++++
 include/net/mac80211.h       |   6 ++
 include/uapi/linux/nl80211.h |   4 +-
 net/mac80211/cfg.c           |  28 +++++++++
 net/mac80211/mlme.c          |  24 ++++++++
 net/wireless/core.c          |  13 ++++
 net/wireless/core.h          |   9 +++
 net/wireless/nl80211.c       | 137 +++++++++++++++++++++++++++++++++++++++----
 net/wireless/rdev-ops.h      |  12 ++++
 net/wireless/trace.h         |  22 +++++++
 10 files changed, 255 insertions(+), 12 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 632dce1..0105e86 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2604,6 +2604,10 @@ struct cfg80211_nan_func {
  *	the current level is above/below the configured threshold; this may
  *	need some care when the configuration is changed (without first being
  *	disabled.)
+ * @set_cqm_rssi_range_config: Configure two RSSI thresholds in the
+ *	connection quality monitor.  Even if the driver implements both the
+ *	single threshold and low/high thresholds mechanisms, it should assume
+ *	only one is active at any time.
  * @set_cqm_txe_config: Configure connection quality monitor TX error
  *	thresholds.
  * @sched_scan_start: Tell the driver to start a scheduled scan.
@@ -2887,6 +2891,10 @@ struct cfg80211_ops {
 				       struct net_device *dev,
 				       s32 rssi_thold, u32 rssi_hyst);
 
+	int	(*set_cqm_rssi_range_config)(struct wiphy *wiphy,
+					     struct net_device *dev,
+					     s32 rssi_low, s32 rssi_high);
+
 	int	(*set_cqm_txe_config)(struct wiphy *wiphy,
 				      struct net_device *dev,
 				      u32 rate, u32 pkts, u32 intvl);
@@ -3709,6 +3717,7 @@ void wiphy_free(struct wiphy *wiphy);
 struct cfg80211_conn;
 struct cfg80211_internal_bss;
 struct cfg80211_cached_keys;
+struct cfg80211_cqm_config;
 
 /**
  * struct wireless_dev - wireless device state
@@ -3769,6 +3778,7 @@ struct cfg80211_cached_keys;
  * @event_list: (private) list for internal event processing
  * @event_lock: (private) lock for event list
  * @owner_nlportid: (private) owner socket port ID
+ * @cqm_config: (private) nl80211 RSSI monitor state
  */
 struct wireless_dev {
 	struct wiphy *wiphy;
@@ -3833,6 +3843,8 @@ struct wireless_dev {
 		bool prev_bssid_valid;
 	} wext;
 #endif
+
+	struct cfg80211_cqm_config *cqm_config;
 };
 
 static inline u8 *wdev_address(struct wireless_dev *wdev)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 33026e1..7da1056 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -502,6 +502,10 @@ struct ieee80211_mu_group_data {
  *	implies disabled. As with the cfg80211 callback, a change here should
  *	cause an event to be sent indicating where the current value is in
  *	relation to the newly configured threshold.
+ * @cqm_rssi_low: Connection quality monitor RSSI lower threshold, a zero value
+ *	implies disabled.  This is an alternative mechanism to the single
+ *	threshold event and can't be enabled simultaneously.
+ * @cqm_rssi_low: Connection quality monitor RSSI upper threshold.
  * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
  * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
  *	may filter ARP queries targeted for other addresses than listed here.
@@ -554,6 +558,8 @@ struct ieee80211_bss_conf {
 	u16 ht_operation_mode;
 	s32 cqm_rssi_thold;
 	u32 cqm_rssi_hyst;
+	s32 cqm_rssi_low;
+	s32 cqm_rssi_high;
 	struct cfg80211_chan_def chandef;
 	struct ieee80211_mu_group_data mu_group;
 	__be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 48108fd..d632c6a 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3839,7 +3839,9 @@ enum nl80211_ps_state {
  * @__NL80211_ATTR_CQM_INVALID: invalid
  * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies
  *	the threshold for the RSSI level at which an event will be sent. Zero
- *	to disable.
+ *	to disable.  Alternatively multiple values can be supplied as a
+ *	low-to-high sorted array of thresholds in dBm.  Events will be sent
+ *	when the RSSI value crosses any of the thresholds.
  * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies
  *	the minimum amount the RSSI level must change after an event before a
  *	new event may be issued (to reduce effects of RSSI oscillation).
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index fd6541f..6ac0523 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2647,6 +2647,33 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
 
 	bss_conf->cqm_rssi_thold = rssi_thold;
 	bss_conf->cqm_rssi_hyst = rssi_hyst;
+	bss_conf->cqm_rssi_low = 0;
+	bss_conf->cqm_rssi_high = 0;
+	sdata->u.mgd.last_cqm_event_signal = 0;
+
+	/* tell the driver upon association, unless already associated */
+	if (sdata->u.mgd.associated &&
+	    sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)
+		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM);
+
+	return 0;
+}
+
+static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy,
+					       struct net_device *dev,
+					       s32 rssi_low, s32 rssi_high)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_vif *vif = &sdata->vif;
+	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+
+	if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)
+		return -EOPNOTSUPP;
+
+	bss_conf->cqm_rssi_low = rssi_low;
+	bss_conf->cqm_rssi_high = rssi_high;
+	bss_conf->cqm_rssi_thold = 0;
+	bss_conf->cqm_rssi_hyst = 0;
 	sdata->u.mgd.last_cqm_event_signal = 0;
 
 	/* tell the driver upon association, unless already associated */
@@ -3645,6 +3672,7 @@ const struct cfg80211_ops mac80211_config_ops = {
 	.mgmt_tx = ieee80211_mgmt_tx,
 	.mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,
 	.set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
+	.set_cqm_rssi_range_config = ieee80211_set_cqm_rssi_range_config,
 	.mgmt_frame_register = ieee80211_mgmt_frame_register,
 	.set_antenna = ieee80211_set_antenna,
 	.get_antenna = ieee80211_get_antenna,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 6898ecb..7f99918 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3416,6 +3416,30 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
+	if (bss_conf->cqm_rssi_low &&
+	    ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
+		int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
+		int last_event = ifmgd->last_cqm_event_signal;
+		int low = bss_conf->cqm_rssi_low;
+		int high = bss_conf->cqm_rssi_high;
+
+		if (sig < low &&
+		    (last_event == 0 || last_event >= low)) {
+			ifmgd->last_cqm_event_signal = sig;
+			ieee80211_cqm_rssi_notify(
+				&sdata->vif,
+				NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+				sig, GFP_KERNEL);
+		} else if (sig > high &&
+			   (last_event == 0 || last_event <= high)) {
+			ifmgd->last_cqm_event_signal = sig;
+			ieee80211_cqm_rssi_notify(
+				&sdata->vif,
+				NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+				sig, GFP_KERNEL);
+		}
+	}
+
 	if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) {
 		mlme_dbg_ratelimited(sdata,
 				     "cancelling AP probe due to a received beacon\n");
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 8201e6d..f6c1bf2 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -928,6 +928,16 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
 }
 EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
 
+void cfg80211_cqm_config_free(struct wireless_dev *wdev)
+{
+	if (!wdev->cqm_config)
+		return;
+
+	kfree(wdev->cqm_config->rssi_thresholds);
+	kfree(wdev->cqm_config);
+	wdev->cqm_config = NULL;
+}
+
 void cfg80211_unregister_wdev(struct wireless_dev *wdev)
 {
 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
@@ -954,6 +964,8 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
 		WARN_ON_ONCE(1);
 		break;
 	}
+
+	cfg80211_cqm_config_free(wdev);
 }
 EXPORT_SYMBOL(cfg80211_unregister_wdev);
 
@@ -1205,6 +1217,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 #ifdef CONFIG_CFG80211_WEXT
 			kzfree(wdev->wext.keys);
 #endif
+			cfg80211_cqm_config_free(wdev);
 		}
 		/*
 		 * synchronise (so that we won't find this netdev
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 08d2e94..75fc334 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -270,6 +270,13 @@ struct cfg80211_iface_destroy {
 	u32 nlportid;
 };
 
+struct cfg80211_cqm_config {
+	s32 *rssi_thresholds;
+	int n_rssi_thresholds;
+	u32 rssi_hyst;
+	s32 last_rssi_event_value;
+};
+
 void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev);
 
 /* free object */
@@ -504,4 +511,6 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
 #define CFG80211_DEV_WARN_ON(cond)	({bool __r = (cond); __r; })
 #endif
 
+void cfg80211_cqm_config_free(struct wireless_dev *wdev);
+
 #endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5d10774..907bd2a 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -9272,7 +9272,7 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
 
 static const struct nla_policy
 nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
-	[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
+	[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_BINARY },
 	[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
 	[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
 	[NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
@@ -9301,28 +9301,127 @@ static int nl80211_set_cqm_txe(struct genl_info *info,
 	return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
 }
 
+static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
+				    struct net_device *dev)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	s32 last, low, high;
+	u32 hyst;
+	int i, n;
+	int err;
+
+	/* RSSI reporting disabled? */
+	if (!wdev->cqm_config)
+		return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
+
+	/*
+	 * Obtain current RSSI value if possible, if not and no RSSI threshold
+	 * event has been received yet, we should receive an event after a
+	 * connection is established and enough beacons received to calculate
+	 * the average.
+	 */
+	if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss) {
+		struct station_info sinfo;
+		u8 *mac_addr;
+
+		mac_addr = wdev->current_bss->pub.bssid;
+
+		err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
+		if (err)
+			return err;
+
+		if (sinfo.filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
+			wdev->cqm_config->last_rssi_event_value =
+				(s8) sinfo.rx_beacon_signal_avg;
+	}
+
+	last = wdev->cqm_config->last_rssi_event_value;
+	hyst = wdev->cqm_config->rssi_hyst;
+	n = wdev->cqm_config->n_rssi_thresholds;
+
+	for (i = 0; i < n; i++)
+		if (last < wdev->cqm_config->rssi_thresholds[i])
+			break;
+
+	low = i > 0 ? wdev->cqm_config->rssi_thresholds[i - 1] : S32_MIN;
+	high = i < n ? wdev->cqm_config->rssi_thresholds[i] : S32_MAX;
+
+	if (low > (s32) (last - hyst))
+		low = last - hyst;
+	if (high < (s32) (last + hyst))
+		high = last + hyst;
+
+	return rdev_set_cqm_rssi_range_config(rdev, dev, low, high - 1);
+}
+
 static int nl80211_set_cqm_rssi(struct genl_info *info,
-				s32 threshold, u32 hysteresis)
+				const s32 *thresholds, int n_thresholds,
+				u32 hysteresis)
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
 	struct net_device *dev = info->user_ptr[1];
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int i, err;
+	s32 prev = S32_MIN;
 
-	if (threshold > 0)
-		return -EINVAL;
+	/* Check all values negative and sorted */
+	for (i = 0; i < n_thresholds; i++) {
+		if (thresholds[i] > 0 || thresholds[i] <= prev)
+			return -EINVAL;
+
+		prev = thresholds[i];
+	}
+
+	if (n_thresholds == 1 && thresholds[0] == 0)
+		n_thresholds = 0;
 
 	/* disabling - hysteresis should also be zero then */
-	if (threshold == 0)
+	if (n_thresholds == 0)
 		hysteresis = 0;
 
-	if (!rdev->ops->set_cqm_rssi_config)
-		return -EOPNOTSUPP;
-
 	if (wdev->iftype != NL80211_IFTYPE_STATION &&
 	    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
 		return -EOPNOTSUPP;
 
-	return rdev_set_cqm_rssi_config(rdev, dev, threshold, hysteresis);
+	wdev_lock(wdev);
+	cfg80211_cqm_config_free(wdev);
+	wdev_unlock(wdev);
+
+	if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) {
+		const s32 disable = 0;
+
+		if (n_thresholds == 0) {
+			n_thresholds = 1;
+			thresholds = &disable;
+		}
+
+		return rdev_set_cqm_rssi_config(rdev, dev,
+						thresholds[0], hysteresis);
+	}
+
+	if (!rdev->ops->set_cqm_rssi_range_config || !rdev->ops->get_station)
+		return -EOPNOTSUPP;
+
+	wdev_lock(wdev);
+	if (n_thresholds) {
+		struct cfg80211_cqm_config *cqm_config;
+
+		cqm_config = kzalloc(sizeof(struct cfg80211_cqm_config),
+					   GFP_KERNEL);
+		cqm_config->rssi_thresholds =
+			kmemdup(thresholds, n_thresholds * sizeof(s32),
+				GFP_KERNEL);
+		cqm_config->n_rssi_thresholds = n_thresholds;
+		cqm_config->rssi_hyst = hysteresis;
+
+		wdev->cqm_config = cqm_config;
+	}
+
+	err = cfg80211_cqm_rssi_update(rdev, dev);
+
+	wdev_unlock(wdev);
+
+	return err;
 }
 
 static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
@@ -9342,10 +9441,15 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
 
 	if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
 	    attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
-		s32 threshold = nla_get_s32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
+		s32 *thresholds = nla_data(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
+		int len = nla_len(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
 		u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
 
-		return nl80211_set_cqm_rssi(info, threshold, hysteresis);
+		if (len % 4)
+			return -EINVAL;
+
+		return nl80211_set_cqm_rssi(info, thresholds, len / 4,
+					    hysteresis);
 	}
 
 	if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
@@ -13741,6 +13845,8 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 			      s32 rssi_level, gfp_t gfp)
 {
 	struct sk_buff *msg;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
 
 	trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
 
@@ -13748,6 +13854,15 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 		    rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
 		return;
 
+	if (wdev->cqm_config) {
+		wdev->cqm_config->last_rssi_event_value = rssi_level;
+
+		cfg80211_cqm_rssi_update(rdev, dev);
+
+		if (rssi_level == 0)
+			rssi_level = wdev->cqm_config->last_rssi_event_value;
+	}
+
 	msg = cfg80211_prepare_cqm(dev, NULL, gfp);
 	if (!msg)
 		return;
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 11cf83c..ae180f3 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -726,6 +726,18 @@ rdev_set_cqm_rssi_config(struct cfg80211_registered_device *rdev,
 }
 
 static inline int
+rdev_set_cqm_rssi_range_config(struct cfg80211_registered_device *rdev,
+			       struct net_device *dev, s32 low, s32 high)
+{
+	int ret;
+	trace_rdev_set_cqm_rssi_range_config(&rdev->wiphy, dev, low, high);
+	ret = rdev->ops->set_cqm_rssi_range_config(&rdev->wiphy, dev,
+						   low, high);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+	return ret;
+}
+
+static inline int
 rdev_set_cqm_txe_config(struct cfg80211_registered_device *rdev,
 			struct net_device *dev, u32 rate, u32 pkts, u32 intvl)
 {
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 6ac46a0..993f661 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1304,6 +1304,28 @@ TRACE_EVENT(rdev_set_cqm_rssi_config,
 		 __entry->rssi_thold, __entry->rssi_hyst)
 );
 
+TRACE_EVENT(rdev_set_cqm_rssi_range_config,
+	TP_PROTO(struct wiphy *wiphy,
+		 struct net_device *netdev, s32 low, s32 high),
+	TP_ARGS(wiphy, netdev, low, high),
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		NETDEV_ENTRY
+		__field(s32, rssi_low)
+		__field(s32, rssi_high)
+	),
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		NETDEV_ASSIGN;
+		__entry->rssi_low = low;
+		__entry->rssi_high = high;
+	),
+	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT
+		  ", range: %d - %d ",
+		  WIPHY_PR_ARG, NETDEV_PR_ARG,
+		  __entry->rssi_low, __entry->rssi_high)
+);
+
 TRACE_EVENT(rdev_set_cqm_txe_config,
 	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 rate,
 		 u32 pkts, u32 intvl),
-- 
2.7.4

^ permalink raw reply related

* [PATCH v8] mac80211: multicast to unicast conversion
From: Michael Braun @ 2016-11-22 10:52 UTC (permalink / raw)
  To: johannes; +Cc: Michael Braun, linux-wireless, netdev, projekt-wlan

Add the ability for an AP (and associated VLANs) to perform
multicast-to-unicast conversion for ARP, IPv4 and IPv6 frames
(possibly within 802.1Q). If enabled, such frames are to be sent
to each station separately, with the DA replaced by their own
MAC address rather than the group address.

Note that this may break certain expectations of the receiver,
such as the ability to drop unicast IP packets received within
multicast L2 frames, or the ability to not send ICMP destination
unreachable messages for packets received in L2 multicast (which
is required, but the receiver can't tell the difference if this
new option is enabled.)

This also doesn't implement the 802.11 DMS (directed multicast
service).

Signed-off-by: Michael Braun <michael-dev@fami-braun.de>

--
v8:
  - remove superflous check
  - change return type to bool
v7:
  - avoid recursion
  - style and description
v5:
  - rename bss->unicast to bss->multicast_to_unicast
  - access sdata->bss only after checking iftype
v4:
  - rename MULTICAST_TO_UNICAST to MULTICAST_TO_UNICAST
v3: fix compile error for trace.h
v2: add nl80211 toggle
    rename tx_dnat to change_da
    change int to bool unicast
---
 net/mac80211/cfg.c            |  12 +++++
 net/mac80211/debugfs_netdev.c |   3 ++
 net/mac80211/ieee80211_i.h    |   1 +
 net/mac80211/tx.c             | 122 +++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 137 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 1edb017..7de342a 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3345,6 +3345,17 @@ static int ieee80211_del_tx_ts(struct wiphy *wiphy, struct net_device *dev,
 	return -ENOENT;
 }
 
+static int ieee80211_set_multicast_to_unicast(struct wiphy *wiphy,
+					      struct net_device *dev,
+					      const bool enabled)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	sdata->u.ap.multicast_to_unicast = enabled;
+
+	return 0;
+}
+
 const struct cfg80211_ops mac80211_config_ops = {
 	.add_virtual_intf = ieee80211_add_iface,
 	.del_virtual_intf = ieee80211_del_iface,
@@ -3430,4 +3441,5 @@ const struct cfg80211_ops mac80211_config_ops = {
 	.set_ap_chanwidth = ieee80211_set_ap_chanwidth,
 	.add_tx_ts = ieee80211_add_tx_ts,
 	.del_tx_ts = ieee80211_del_tx_ts,
+	.set_multicast_to_unicast = ieee80211_set_multicast_to_unicast,
 };
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index ed7bff4..509c6c3 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -487,6 +487,8 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast(
 }
 IEEE80211_IF_FILE_R(num_buffered_multicast);
 
+IEEE80211_IF_FILE(multicast_to_unicast, u.ap.multicast_to_unicast, HEX);
+
 /* IBSS attributes */
 static ssize_t ieee80211_if_fmt_tsf(
 	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
@@ -642,6 +644,7 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
 	DEBUGFS_ADD(dtim_count);
 	DEBUGFS_ADD(num_buffered_multicast);
 	DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
+	DEBUGFS_ADD_MODE(multicast_to_unicast, 0600);
 }
 
 static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 70c0963..84374ed 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -293,6 +293,7 @@ struct ieee80211_if_ap {
 			 driver_smps_mode; /* smps mode request */
 
 	struct work_struct request_smps_work;
+	bool multicast_to_unicast;
 };
 
 struct ieee80211_if_wds {
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index c3ce86e..5effffd 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/skbuff.h>
+#include <linux/if_vlan.h>
 #include <linux/etherdevice.h>
 #include <linux/bitmap.h>
 #include <linux/rcupdate.h>
@@ -3418,6 +3419,115 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
 	rcu_read_unlock();
 }
 
+static int ieee80211_change_da(struct sk_buff *skb, struct sta_info *sta)
+{
+	struct ethhdr *eth;
+	int err;
+
+	err = skb_ensure_writable(skb, ETH_HLEN);
+	if (unlikely(err))
+		return err;
+
+	eth = (void *)skb->data;
+	ether_addr_copy(eth->h_dest, sta->sta.addr);
+
+	return 0;
+}
+
+static inline bool
+ieee80211_multicast_to_unicast(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	const struct ethhdr *eth = (void *)skb->data;
+	const struct vlan_ethhdr *ethvlan = (void *)skb->data;
+	u16 ethertype;
+
+	if (likely(!is_multicast_ether_addr(eth->h_dest)))
+		return 0;
+
+	switch (sdata->vif.type) {
+	case NL80211_IFTYPE_AP_VLAN:
+		if (sdata->u.vlan.sta)
+			return 0;
+		if (sdata->wdev.use_4addr)
+			return 0;
+		/* fall through */
+	case NL80211_IFTYPE_AP:
+		/* check runtime toggle for this bss */
+		if (!sdata->bss->multicast_to_unicast)
+			return 0;
+		break;
+	default:
+		return 0;
+	}
+
+	/* multicast to unicast conversion only for some payload */
+	ethertype = ntohs(eth->h_proto);
+	if (ethertype == ETH_P_8021Q && skb->len >= VLAN_ETH_HLEN)
+		ethertype = ntohs(ethvlan->h_vlan_encapsulated_proto);
+	switch (ethertype) {
+	case ETH_P_ARP:
+	case ETH_P_IP:
+	case ETH_P_IPV6:
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+ieee80211_convert_to_unicast(struct sk_buff *skb, struct net_device *dev,
+			     struct sk_buff_head *queue)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
+	const struct ethhdr *eth = (struct ethhdr *)skb->data;
+	struct sta_info *sta, *first = NULL;
+	struct sk_buff *cloned_skb;
+
+	rcu_read_lock();
+
+	list_for_each_entry_rcu(sta, &local->sta_list, list) {
+		if (sdata != sta->sdata)
+			/* AP-VLAN mismatch */
+			continue;
+		if (unlikely(ether_addr_equal(eth->h_source, sta->sta.addr)))
+			/* do not send back to source */
+			continue;
+		if (!first) {
+			first = sta;
+			continue;
+		}
+		cloned_skb = skb_clone(skb, GFP_ATOMIC);
+		if (!cloned_skb)
+			goto unicast;
+		if (unlikely(ieee80211_change_da(cloned_skb, sta))) {
+			dev_kfree_skb(cloned_skb);
+			goto unicast;
+		}
+		__skb_queue_tail(queue, cloned_skb);
+	}
+
+	if (likely(first)) {
+		if (unlikely(ieee80211_change_da(skb, first)))
+			goto unicast;
+		__skb_queue_tail(queue, skb);
+	} else {
+		/* no STA connected, drop */
+		kfree_skb(skb);
+		skb = NULL;
+	}
+
+	goto out;
+unicast:
+	__skb_queue_purge(queue);
+	__skb_queue_tail(queue, skb);
+out:
+	rcu_read_unlock();
+}
+
 /**
  * ieee80211_subif_start_xmit - netif start_xmit function for 802.3 vifs
  * @skb: packet to be sent
@@ -3428,7 +3538,17 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
 netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
 				       struct net_device *dev)
 {
-	__ieee80211_subif_start_xmit(skb, dev, 0);
+	if (unlikely(ieee80211_multicast_to_unicast(skb, dev))) {
+		struct sk_buff_head queue;
+
+		__skb_queue_head_init(&queue);
+		ieee80211_convert_to_unicast(skb, dev, &queue);
+		while ((skb = __skb_dequeue(&queue)))
+			__ieee80211_subif_start_xmit(skb, dev, 0);
+	} else {
+		__ieee80211_subif_start_xmit(skb, dev, 0);
+	}
+
 	return NETDEV_TX_OK;
 }
 
-- 
2.1.4

^ permalink raw reply related

* Re: Break-it testing for wifi
From: Johannes Berg @ 2016-11-22 10:56 UTC (permalink / raw)
  To: Ben Greear, linux-wireless@vger.kernel.org
In-Reply-To: <a60dac22-655e-ea93-61c2-73db05a47572@candelatech.com>

On Mon, 2016-11-21 at 08:10 -0800, Ben Greear wrote:

> I am thinking about adding some sort of framework to wpa_supplicant
> and/or the mac80211 stack to allow purposefully creating bad station
> behaviour in order to test robustness of APs.

I'm interested in this.

Have you seen the fuzzer stuff in wpa_s/hostapd?

See

https://w1.fi/cgit/hostap/commit/?id=7d3f18d72c3c883112ee927fc402c0eaed09ff65

for example for something Jouni did after our discussions recently.

> Some ideas so far:
> 
> 1)  Allow supplicant to do bad state-machine transitions (start 4-way 
> before associating, for instance).

Why would you do that? In order to test the AP implementation?

> 2)  Randomly corrupt mgt frames in driver and/or mac80211 stack
> and/or supplicant.

I think fuzzing the input path for those frames would be more useful
than just corrupting things.

> 3)  Possibly allow user to make specific corruptions.  This would
> probably be in supplicant
>      only, and I am not sure how this would be configured.  Maybe
> allow user to over-ride
>      existing IEs and add bogus ones of their own choosing.

No idea what you really mean by this :)

> 4)  Maybe some specific tests like putting in over-flow sized lengths
> of IEs.

Again, fuzzing would cover this?

> Has anyone done anything similar they would like to share?
> 
> Johannes:  Any interest in having such a framework in upstream
> kernels?

I suspect you have something entirely different in mind, like testing a
(remote) AP implementation?

All of the local testing is probably better done via hwsim?

johannes

^ permalink raw reply

* [PATCH] ath9k: feed only active spectral / dfs-detector
From: Zefir Kurtisi @ 2016-11-22 11:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, michal.kazior, benjamin

Radar pulse and spectral scan reports are provided by the HW
with the ATH9K_RXERR_PHY flag set. Those are forwarded to
the dfs-detector and spectral module for further processing.

For some older chips, the pre-conditions checked in those
modules are ambiguous, since ATH9K_PHYERR_RADAR is used to
tag both types. As a result, spectral frames are fed into
the dfs-detector and vice versa.

This could lead to a false radar detection on a non-DFS
channel (which is uncritical), but more relevant it causes
useless CPU load for processing invalid frames.

This commit ensures that the dfs-detector and spectral
collector are only fed when they are active.

Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
---
 drivers/net/wireless/ath/ath9k/recv.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 6697342..48f8af1 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -867,10 +867,21 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 	 * can be dropped.
 	 */
 	if (rx_stats->rs_status & ATH9K_RXERR_PHY) {
-		ath9k_dfs_process_phyerr(sc, hdr, rx_stats, rx_status->mactime);
-		if (ath_cmn_process_fft(&sc->spec_priv, hdr, rx_stats, rx_status->mactime))
+		/*
+		 * DFS and spectral are mutually exclusive
+		 *
+		 * Since some chips use PHYERR_RADAR as indication for both, we
+		 * need to double check which feature is enabled to prevent
+		 * feeding spectral or dfs-detector with wrong frames.
+		 */
+		if (hw->conf.radar_enabled) {
+			ath9k_dfs_process_phyerr(sc, hdr, rx_stats,
+						 rx_status->mactime);
+		} else if (sc->spec_priv.spectral_mode != SPECTRAL_DISABLED &&
+			   ath_cmn_process_fft(&sc->spec_priv, hdr, rx_stats,
+					       rx_status->mactime)) {
 			RX_STAT_INC(rx_spectral);
-
+		}
 		return -EINVAL;
 	}
 
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH 0/7] rtl8xxxu: Pending patches
From: Barry Day @ 2016-11-22 12:26 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: linux-wireless, kvalo, Larry.Finger
In-Reply-To: <wrfj7f7w7oqk.fsf@redhat.com>

On Mon, Nov 21, 2016 at 11:59:47AM -0500, Jes Sorensen wrote:
> Barry Day <briselec@gmail.com> writes:
> > On Sat, Nov 19, 2016 at 06:53:42PM -0500, Jes Sorensen wrote:
> >> Barry Day <briselec@gmail.com> writes:
> >> > On Fri, Nov 18, 2016 at 09:00:10PM -0500, Jes Sorensen wrote:
> >> >> Barry Day <briselec@gmail.com> writes:
> >> >> > On Fri, Nov 18, 2016 at 04:44:21PM -0500, Jes.Sorensen@redhat.com wrote:
> >> >> >> From: Jes Sorensen <Jes.Sorensen@redhat.com>
> >> >> >> 
> >> >> >> Kalle,
> >> >> >> 
> >> >> >> Please find attached a number of patches for the rtl8xxxu
> >> >> >> driver.
> >> >> >> 
> >> >> >> The issues reported with wpa_supplicant on 8723bu still needs further
> >> >> >> investigation.
> >> >> >> 
> >> >> >
> >> >> > The patch I posted that you want tested more will also fix the
> >> >> > wpa_supplicant issue.  Currently I'm looking at why the tx rate is not
> >> >> > what it should be. I feel fixing that first will be beneficial for
> >> >> > fixing any other issues.
> >> >> 
> >> >> Interesting, I was thinking that might be the case. I do want to dig
> >> >> into this further to understand it better. If we use your solution I
> >> >> will want to make sure we cover both gen1 and gen2 parts.
> >> >> 
> >> >> > The recent merge has made my local branch of rtl8xxxu-devel 14
> >> >> > commits ahead.
> >> >> > Do I need to do a reset and submit a new patch for the DWA-131 dongle?
> >> >> 
> >> >> In general you need to use 'git pull --rebase' on my tree. I rebase it
> >> >> to stay in sync with Kalle's tree.
> >> >> 
> >> >> The DWA-131 is the 8192eu? Sorry a bit behind and my mind is losing
> >> >> bits. If it's the patch you posted earlier I can dig it out and play
> >> >> with it - I am still catching up though, so please be patient.
> >> >
> >> > yes it's an 8192eu.
> >> 
> >> Gotcha - how do you do your testing to reproduce the problem btw? Most
> >> of my testing is using the 8723au as a primary device and the next
> >> device as a follow-on, so I may not see as long a run with the device
> >> active as you see.
> >> 
> >
> > Testing is simple. Connect to an AP in the usual
> > manner..disconnect..reconnect.  The 8192eu will fail to reconnect and
> > John Heenan reported the 8723bu also fails to reconnect. Even though
> > he was directly stopping and restarting wpa_supplicant, it's the same
> > thing to the driver - connect..disconnect..reconnect.
> 
> Thanks for the details - I'll have a look shortly.
> 
> > With using a usb_device pointer, each message starts with the usb bus
> > address.  Plug it into a different port and that address could
> > change. By using a pointer to the device associated with the wiphy
> > each message will begin with the driver name. Just makes it easier for
> > the average user to report what's in the log because he can just grep
> > for "rtl8xxxu".
> 
> I see - that would be problematic for me as I quite often have 3-4 of
> these things plugged in at the same time. Not knowing which port spits
> out the message would make it a lot harder to track. In fact my primary
> devel box for this (Lenovo Yoga 13) has an rtl8723au soldered on the
> motherboard, so the moment I plug in any other dongle I'll have two.
> 
> The alternative would be to add a prefer to the individual messages.
> 
> Cheers,
> Jes

I should have mentioned it also places the usb address after the driver name.

^ permalink raw reply

* Re: [PATCH] rtl8xxxu: Fix failure to reconnect to AP
From: Barry Day @ 2016-11-22 12:53 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: Kalle Valo, linux-wireless
In-Reply-To: <wrfjbmx87oul.fsf@redhat.com>

On Mon, Nov 21, 2016 at 11:57:22AM -0500, Jes Sorensen wrote:
> Jes Sorensen <Jes.Sorensen@redhat.com> writes:
> > Barry Day <briselec@gmail.com> writes:
> >> The rtl8192e and rtl8723 fail to reconnect to an AP after being
> >> disconnected. Ths patch fixes that without affecting the rtl8192cu.
> >> I don't have a rtl8723 to test but it has been tested on a rtl8192eu.
> >> After going through the orginal realtek code for the rtl8723, I am
> >> confident the patch is applicable to both.
> >>
> >> Signed-off-by: Barry Day <briselec@gmail.com>
> >> ---
> >>  rtl8xxxu_core.c | 18 ++++++++++++++----
> >>  1 file changed, 14 insertions(+), 4 deletions(-)
> >
> > Hi Barry,
> >
> > Thank you for the patch. There are a couple of items which I am not
> > 100% sure about the order of.
> >
> >> diff --git a/rtl8xxxu_core.c b/rtl8xxxu_core.c
> >> index 04141e5..6ac10d2 100644
> >> --- a/rtl8xxxu_core.c
> >> +++ b/rtl8xxxu_core.c
> >> @@ -4372,17 +4372,25 @@ void rtl8xxxu_gen1_report_connect(struct rtl8xxxu_priv *priv,
> >>  void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv,
> >>  				  u8 macid, bool connect)
> >>  {
> >> +	u8 val8;
> >>  	struct h2c_cmd h2c;
> >>  
> >>  	memset(&h2c, 0, sizeof(struct h2c_cmd));
> >>  
> >>  	h2c.media_status_rpt.cmd = H2C_8723B_MEDIA_STATUS_RPT;
> >> -	if (connect)
> >> +	if (connect) {
> >>  		h2c.media_status_rpt.parm |= BIT(0);
> >> -	else
> >> -		h2c.media_status_rpt.parm &= ~BIT(0);
> >> +		rtl8xxxu_gen2_h2c_cmd(priv, &h2c,
> >> +					sizeof(h2c.media_status_rpt));
> >> +	} else {
> >> +		val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
> >> +		val8 &= ~BEACON_FUNCTION_ENABLE;
> >> +
> >> +		rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
> >> +		rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x00);
> >> +		rtl8xxxu_write8(priv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1)));
> >> +	}
> >>  
> >> -	rtl8xxxu_gen2_h2c_cmd(priv, &h2c, sizeof(h2c.media_status_rpt));
> >>  }
> 
> Barry,
> 
> So looking at this again, I am pretty sure you will break monitor mode
> with this. By setting REG_RXFLTMAP2 to 0x0000 you stop reception of all
> data frames.
> 
> The other thing here is that you change removes the part notifying the
> firmware that we disconnected since you now only send the
> media_start_rpt command on connect, but not on disconnect.
> 
> I am curious if the problem goes away if you simply add the BEACON_CTRL
> and REG_DUAL_TSF_RST parts?
> 
> >
> > This only affects 8192eu and not 8192cu - we left RXFLTMAP2 out of here
> > on purpose for monitor mode, but you now disable it for 8192eu/8723bu.
> >
> >>  void rtl8xxxu_gen1_init_aggregation(struct rtl8xxxu_priv *priv)
> >> @@ -4515,6 +4523,8 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
> >>  				sgi = 1;
> >>  			rcu_read_unlock();
> >>  
> >> +			rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0xffff);
> >> +
> >>  			priv->fops->update_rate_mask(priv, ramask, sgi);
> >>  
> >>  			rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff);
> 
> I believe this change only matters because you disable RXFLTMAP2
> above. If we really have to write to RXFLTMAP2 to make this work, I
> suspect we need to keep some sort of state information.
> 
> I would also be curious if RXFLTMAP2 gets reset somehow by the firmware,
> and we do not account for that.
> 
> Cheers,
> Jes
> 

I'll redo the patch without touching REG_RXFLTMAP2. I don't think it's needed
to fix the fail to reconnect issue.

I haven't had a proper look at the 8723 chips yet but the vendor drivers for
the others don't do a h2c cmd for disconnect but I'll test leaving it in to see
if it makes any difference. A 8723bu arrived in the mail today so now I can
test it too and I discovered yesterday I have a 8723au but it's in a cheap
Android tablet.

Barry

^ permalink raw reply

* Re: scheduled scan interval
From: Arend Van Spriel @ 2016-11-22 13:09 UTC (permalink / raw)
  To: Luca Coelho, Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1479806342.2517.44.camel@coelho.fi>

On 22-11-2016 10:19, Luca Coelho wrote:
> On Tue, 2016-11-22 at 10:10 +0100, Arend Van Spriel wrote:
>> On 22-11-2016 6:59, Luca Coelho wrote:
>>> Oh, I see.  The problem is that the "max_sched_scan_plan_interval" was
>>> introduced later.  If the userspace passes
>>> NL80211__ATTR_SCHED_SCAN_INTERVAL, it probably means that it doesn't
>>> know about NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL (i.e. it's only using an
>>> old API).  If it is also, for some reason, passing a very large number,
>>> we shouldn't suddenly make it fail with -EINVALID, because that would
>>> be a break of UABI.  And since we know the driver cannot support such a
>>> large number, we cap it because it's the best we can do.
>>>
>>> Now, if the userspace uses NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL, it
>>> means that it knows the new API (and was written after the new API was
>>> introduced), so we can be stricter and assume it must have checked
>>> NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL.
>>>
>>> Makes sense?
>>
>> Not really. As you say if user-space passes
>> NL80211_ATTR_SCHED_SCAN_INTERVAL it is using old API. Otherwise it
>> should pass NL80211_ATTR_SCHED_SCAN_PLANS.
> 
> Errr... I meant "if the userspace uses NL80211_ATTR_SCHED_SCAN_PLANS",
> pasted the wrong thing. ;)
> 
> 
>> If the driver doesn't set the max_sched_scan_plan_interval, mac80211's
>>> default of MAX_U32 will be used:
>>>
>>> struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
>>> 			   const char *requested_name)
>>> {
>>> [...]
>>> 	rdev->wiphy.max_sched_scan_plans = 1;
>>> 	rdev->wiphy.max_sched_scan_plan_interval = U32_MAX;
>>>
>>> 	return &rdev->wiphy;
>>> }
>>> EXPORT_SYMBOL(wiphy_new_nm);
>>>
>>> ...so max_sched_scan_plan_interval will never be zero, unless the
>>> driver explicitly sets it to zero.
>>
>> I think you are overlooking the cfg80211-based drivers here. According
>> to lxr at least brcmfmac, mwifiex, and ath6kl are not specifying it.
>> "Funny" detail is that scheduled scan support in mwifiex seems to be
>> introduced after the scan plan API change.
> 
> You're right, I did overlook non-mac80211 drivers.

Actually, you are referring to wiphy_new_nm() which is obviously used
for cfg80211-based drivers as well. So I will ask to drop my patch.

Regards,
Arend

^ permalink raw reply

* Re: [PATCH] nl80211: change validation of scheduled scan interval values
From: Arend Van Spriel @ 2016-11-22 13:12 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1479810126-28492-1-git-send-email-arend.vanspriel@broadcom.com>

On 22-11-2016 11:22, Arend van Spriel wrote:
> When user-space does not provide scheduled scan plans, ie. uses the
> old scheduled scan API containing NL80211_ATTR_SCHED_SCAN_INTERVAL.
> The interval value passed by user-space is validated against
> struct wiphy::max_sched_scan_plan_interval and if it is exceeding
> it the interval is set to struct wiphy::max_sched_scan_plan_interval.
> However, when the driver does not set this limit the interval the
> interval in the request will always be zero. Hence add a check to
> see whether the driver set struct wiphy::max_sched_scan_plan_interval.
> 
> For the new API, ie. for scheduled scan plans, the interval validation
> has been simalarly adjusted to assure the limit is non-zero.

Actually turns out that max_sched_scan_plan_interval is always set in
wiphy_new_nm() which is used by all drivers so please drop this patch.

Regards,
Arend

> Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
> ---
>  net/wireless/nl80211.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
> index 24ab199..e621554 100644
> --- a/net/wireless/nl80211.c
> +++ b/net/wireless/nl80211.c
> @@ -6777,7 +6777,8 @@ static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
>  		if (!request->scan_plans[0].interval)
>  			return -EINVAL;
>  
> -		if (request->scan_plans[0].interval >
> +		if (wiphy->max_sched_scan_plan_interval &&
> +		    request->scan_plans[0].interval >
>  		    wiphy->max_sched_scan_plan_interval)
>  			request->scan_plans[0].interval =
>  				wiphy->max_sched_scan_plan_interval;
> @@ -6801,7 +6802,10 @@ static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
>  
>  		request->scan_plans[i].interval =
>  			nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_INTERVAL]);
> -		if (!request->scan_plans[i].interval ||
> +		if (!request->scan_plans[i].interval)
> +			return -EINVAL;
> +
> +		if (wiphy->max_sched_scan_plan_interval &&
>  		    request->scan_plans[i].interval >
>  		    wiphy->max_sched_scan_plan_interval)
>  			return -EINVAL;
> 

^ permalink raw reply

* Re: [PATCH] nl80211: change validation of scheduled scan interval values
From: Luca Coelho @ 2016-11-22 13:17 UTC (permalink / raw)
  To: Arend Van Spriel, Johannes Berg; +Cc: linux-wireless
In-Reply-To: <9fa76f2c-44b2-9782-8636-09afd1d59927@broadcom.com>

On Tue, 2016-11-22 at 14:12 +0100, Arend Van Spriel wrote:
> On 22-11-2016 11:22, Arend van Spriel wrote:
> > When user-space does not provide scheduled scan plans, ie. uses the
> > old scheduled scan API containing NL80211_ATTR_SCHED_SCAN_INTERVAL.
> > The interval value passed by user-space is validated against
> > struct wiphy::max_sched_scan_plan_interval and if it is exceeding
> > it the interval is set to struct wiphy::max_sched_scan_plan_interval.
> > However, when the driver does not set this limit the interval the
> > interval in the request will always be zero. Hence add a check to
> > see whether the driver set struct wiphy::max_sched_scan_plan_interval.
> > 
> > For the new API, ie. for scheduled scan plans, the interval validation
> > has been simalarly adjusted to assure the limit is non-zero.
> 
> Actually turns out that max_sched_scan_plan_interval is always set in
> wiphy_new_nm() which is used by all drivers so please drop this patch.

Right, I mixed mac80211 into the picture and got confused.

--
Luca.

^ permalink raw reply

* [PATCH] nl80211: provide minimum scheduled scan (plan) interval
From: Arend van Spriel @ 2016-11-22 13:31 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel

The interval for scheduled scan may have a minimum value for
the device. Allow drivers to specify a minimum value in the
struct wiphy so user-space interval values can be validated
against it.

Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
 include/net/cfg80211.h       |  3 +++
 include/uapi/linux/nl80211.h |  2 ++
 net/wireless/nl80211.c       | 12 ++++++++++++
 3 files changed, 17 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 2019310..ef5d6ab 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3427,6 +3427,8 @@ struct wiphy_iftype_ext_capab {
  *	scans
  * @max_sched_scan_plans: maximum number of scan plans (scan interval and number
  *	of iterations) for scheduled scan supported by the device.
+ * @min_sched_scan_plan_interval: minimum interval (in seconds) for a
+ *	single scan plan supported by the device.
  * @max_sched_scan_plan_interval: maximum interval (in seconds) for a
  *	single scan plan supported by the device.
  * @max_sched_scan_plan_iterations: maximum number of iterations for a single
@@ -3552,6 +3554,7 @@ struct wiphy {
 	u16 max_scan_ie_len;
 	u16 max_sched_scan_ie_len;
 	u32 max_sched_scan_plans;
+	u32 min_sched_scan_plan_interval;
 	u32 max_sched_scan_plan_interval;
 	u32 max_sched_scan_plan_iterations;
 
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 259c9c7..77fc77a 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2381,6 +2381,8 @@ enum nl80211_attrs {
 
 	NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED,
 
+	NL80211_ATTR_MIN_SCAN_PLAN_INTERVAL,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 24ab199..47aca56 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1474,6 +1474,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
 				rdev->wiphy.max_sched_scan_plans) ||
 		    nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
 				rdev->wiphy.max_sched_scan_plan_interval) ||
+		    nla_put_u32(msg, NL80211_ATTR_MIN_SCAN_PLAN_INTERVAL,
+				rdev->wiphy.min_sched_scan_plan_interval) ||
 		    nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
 				rdev->wiphy.max_sched_scan_plan_iterations))
 			goto nla_put_failure;
@@ -6777,6 +6779,12 @@ static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
 		if (!request->scan_plans[0].interval)
 			return -EINVAL;
 
+		if (wiphy->min_sched_scan_plan_interval &&
+		    request->scan_plans[0].interval <
+		    wiphy->min_sched_scan_plan_interval)
+			request->scan_plans[0].interval =
+				wiphy->min_sched_scan_plan_interval;
+
 		if (request->scan_plans[0].interval >
 		    wiphy->max_sched_scan_plan_interval)
 			request->scan_plans[0].interval =
@@ -6805,6 +6813,10 @@ static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
 		    request->scan_plans[i].interval >
 		    wiphy->max_sched_scan_plan_interval)
 			return -EINVAL;
+		if (wiphy->min_sched_scan_plan_interval &&
+		    request->scan_plans[i].interval <
+		    wiphy->min_sched_scan_plan_interval)
+			return -EINVAL;
 
 		if (plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]) {
 			request->scan_plans[i].iterations =
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH] nl80211: provide minimum scheduled scan (plan) interval
From: Johannes Berg @ 2016-11-22 13:38 UTC (permalink / raw)
  To: Arend van Spriel; +Cc: linux-wireless
In-Reply-To: <1479821515-13261-1-git-send-email-arend.vanspriel@broadcom.com>


> +		if (wiphy->min_sched_scan_plan_interval &&
> +		    request->scan_plans[i].interval <
> +		    wiphy->min_sched_scan_plan_interval)
> +			return -EINVAL;
> 
I'm not sure we should break the API that way - just move it up if it's
smaller?

johannes

^ permalink raw reply

* Re: [RFC] qtn: add FullMAC firmware for Quantenna QSR10G wifi device
From: IgorMitsyanko @ 2016-11-22 14:44 UTC (permalink / raw)
  To: Ben Hutchings, Kyle McMartin
  Cc: Johannes Berg, linux-wireless, btherthala, hwang, smaksimenko,
	dlebed, Igor Mitsyanko, Kamlesh Rath, Sergey Matyukevich,
	Avinash Patil
In-Reply-To: <1478864146.4129.4.camel@sipsolutions.net>

Hi Ben, Kyle,
could you please share what is the position of linux-firmware regarding 
firmware binaries that include GPL components? Does it require entire 
GPL components codebase be present in linux-firmware tree, or maybe 
having this clause in license file is enough:
+Open Source Software. The Software may include components that are licensed
+pursuant to open source software (“Open Source Components”). Information
+regarding the Open Source Components included with the Software is 
available
+upon request to oslegal@quantenna.com. To the extent such Open Source
+Components are required to be licensed to you under the terms of a separate
+license (such as an open source license) then such other terms shall 
apply, and
+nothing herein shall be deemed or interpreted to limit any rights you 
may have
+under any such applicable license.

 From technical perspective, size of the codebase used to build 
Quantenna firmware is a few hundred MBs, it seems too much to include 
into linux-firmware tree.

On 11/11/2016 02:35 PM, Johannes Berg wrote:
> Adding linux-firmware people to Cc, since presumably they don't
> necessarily read linux-wireless...
>
>> Johannes, from that perspective, who are the "redistributors"?
>> Specifically, is linux-firmware git repository considered a
>> redistributor or its just hosting files? I mean, at what moment
>> someone else other then Quantenna will start to be legally obliged to
>> make GPL code used in firmware available for others?
> Look, I don't know. I'd assume people who ship it, like any regular
> distro, would be (re)distributors thereof. "Normal" (non-GPL) firmware
> images come with a redistribution license, but that obviously can't
> work here.
>
> There's some info from Ben here regarding the carl9170 case:
> http://lkml.iu.edu/hypermail/linux/kernel/1605.3/01176.html
>
>> Personally I still hope that linux-firmware itself is not legally
>> concerned with what is the content of firmware its hosting, but looks
>> like there already was a precedent case  with carl9170 driver and
>> we have to somehow deal with it.
> That's really all I wanted to bring up. I'm not involved with the
> linux-firmware git tree.
>
>> There still may be a difference though: Quantenna is semiconductor
>> company only, software
>> used on actual products based on Quantenna chipsets is released by
>> other
>> companies.
>> I just want to present our legal team with a clear case (and position
>> of
>> Linux maintainers) so that they can
>> work with it and make decision on how to proceed.
>>
>>   From technical perspective, as I mentioned, SDK is quite huge and
>> include a lot of opensource
>> components including full Linux, I don't think its reasonable to have
>> it
>> inside linux-firmware tree.
>> What are the options to share it other then providing it on request
>> basis:
>> - git repository
>> - store tarball somewhere on official website
> Clearly that wasn't deemed appropriate for carl9170, so I don't see why
> it'd be different here.
>
> johannes

^ permalink raw reply

* Re: [v5,1/5] soc: qcom: smem_state: Fix include for ERR_PTR()
From: Valo, Kalle @ 2016-11-22 14:55 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: k.eugene.e@gmail.com, Andy Gross, wcn36xx@lists.infradead.org,
	linux-wireless@vger.kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org
In-Reply-To: <20161118183541.GI28340@tuxbot>

Bjorn Andersson <bjorn.andersson@linaro.org> writes:

> On Wed 16 Nov 10:49 PST 2016, Kalle Valo wrote:
>
>> Bjorn Andersson <bjorn.andersson@linaro.org> wrote:
>> > The correct include file for getting errno constants and ERR_PTR() is
>> > linux/err.h, rather than linux/errno.h, so fix the include.
>> >=20
>> > Fixes: e8b123e60084 ("soc: qcom: smem_state: Add stubs for disabled sm=
em_state")
>> > Acked-by: Andy Gross <andy.gross@linaro.org>
>> > Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
>>=20
>> For some reason this fails to compile now. Can you take a look, please?
>>=20
>> ERROR: "qcom_wcnss_open_channel" [drivers/net/wireless/ath/wcn36xx/wcn36=
xx.ko] undefined!
>> make[1]: *** [__modpost] Error 1
>> make: *** [modules] Error 2
>>=20
>> 5 patches set to Changes Requested.
>>=20
>> 9429045 [v5,1/5] soc: qcom: smem_state: Fix include for ERR_PTR()
>> 9429047 [v5,2/5] wcn36xx: Transition driver to SMD client
>
> This patch was updated with the necessary depends in Kconfig to catch
> this exact issue and when I pull in your .config (which has QCOM_SMD=3Dn,
> QCOM_WCNSS_CTRL=3Dn and WCN36XX=3Dy) I can build this just fine.
>
> I've tested the various combinations and it seems to work fine. Do you
> have any other patches in your tree?

This was with the pending branch of my ath.git tree. There are other
wireless patches (ath10k etc) but I would guess they don't affect here.

> Any stale objects?

Not sure what you mean with this question, but I didn't run 'make clean'
if that's what you are asking.

> Would you mind retesting this, before I invest more time in trying to
> reproduce the issue you're seeing?

Sure, I'll take a look but that might take few days.

--=20
Kalle Valo=

^ permalink raw reply

* Re: [PATCH] rtl8xxxu: Fix failure to reconnect to AP
From: Jes Sorensen @ 2016-11-22 15:01 UTC (permalink / raw)
  To: Barry Day; +Cc: Kalle Valo, linux-wireless
In-Reply-To: <20161122125300.GB23278@testbox>

Barry Day <briselec@gmail.com> writes:
> On Mon, Nov 21, 2016 at 11:57:22AM -0500, Jes Sorensen wrote:
>> Jes Sorensen <Jes.Sorensen@redhat.com> writes:
>> >>  void rtl8xxxu_gen1_init_aggregation(struct rtl8xxxu_priv *priv)
>> >> @@ -4515,6 +4523,8 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
>> >>  				sgi = 1;
>> >>  			rcu_read_unlock();
>> >>  
>> >> +			rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0xffff);
>> >> +
>> >>  			priv->fops->update_rate_mask(priv, ramask, sgi);
>> >>  
>> >>  			rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff);
>> 
>> I believe this change only matters because you disable RXFLTMAP2
>> above. If we really have to write to RXFLTMAP2 to make this work, I
>> suspect we need to keep some sort of state information.
>> 
>> I would also be curious if RXFLTMAP2 gets reset somehow by the firmware,
>> and we do not account for that.
>> 
>> Cheers,
>> Jes
>
> I'll redo the patch without touching REG_RXFLTMAP2. I don't think it's needed
> to fix the fail to reconnect issue.
>
> I haven't had a proper look at the 8723 chips yet but the vendor drivers for
> the others don't do a h2c cmd for disconnect but I'll test leaving it in to see
> if it makes any difference. A 8723bu arrived in the mail today so now I can
> test it too and I discovered yesterday I have a 8723au but it's in a cheap
> Android tablet.

Let me know what you find out - if the h2c command causes the failure
that would be very bizarre but certainly interesting to learn.

Cheers,
Jes

^ permalink raw reply

* Re: ath10k stuck in mesh mode
From: Michal Kazior @ 2016-11-22 15:20 UTC (permalink / raw)
  To: Matteo Grandi; +Cc: Bob Copeland, LinuxWireless Mailing List
In-Reply-To: <CAHdg3xadDx=+Yc+vPKtyOG6-w-BRa09OyrE_N09p9juipuur0w@mail.gmail.com>

On 22 November 2016 at 10:43, Matteo Grandi <iu5bdp@gmail.com> wrote:
> Dear Bob, Michal, all
>
> I've finally managed to have a 80MHz channel bandwidth, thanks to your hint!
> The problem was related to the CRDA that even if it looks correctly
> installed, it actually doesn't work as supposed.
> I downloaded and recompiled the CRDA-3.18
> (http://drvbp1.linux-foundation.org/~mcgrof/rel-html/crda/) and set-up
> the regulatory domain.
> Notice that without setting up the reg. domain all the available
> channels have the "passive scanning" label because the CRDA prevent
> beaconing so mesh mode is not possible (maybe it's otherwise possible
> to operate in STA mode that doesn't require to send frames(?)).

STA can be allowed to transmit via beacon hints as far as I understand.


> Now I can have a mesh communication using 80MHz channel bandwidth, but
> MIMO still doesn't work.
> In fact the highest MCS reached was MCS9 that is the highest MCS with
> Single Spatial Stream, and I can't managed to have MIMO.

11n used mcs to imply nss. 11ac treats mcs and nss separately.
Therefore saying "MCS9 is 1SS" is incorrect. How are you checking
this? What device are you using for verifying?


> I played with the antennas position and distance, with the
> polarization and the presence or not of LOS, but by sniffing the
> transmissions I sow only MCS9 even if in the radiotap header field
> there are Antenna 0 and Antenna 1.
> However the radio information field report "Spatial streams: 1".
>
> Does anyone experienced something similar with the use of MIMO in mesh
> mode with the ath10k fw?
> I will thank any light you can shed to this!
> Thank you very much

You might want to debug peer_assoc commands sent to firmware. They may
be, for some reason, be requesting nss=1. Maybe sta_rc_update() isn't
properly updating peer in firmware. Driver debugs/dumps
(debug_mask=0xffffffffff) would be useful.


Michal

^ permalink raw reply

* Re: wl1251 & mac address & calibration data
From: Michal Kazior @ 2016-11-22 15:22 UTC (permalink / raw)
  To: Pali Rohár
  Cc: Kalle Valo, Pavel Machek, Ivaylo Dimitrov, Sebastian Reichel,
	Aaro Koskinen, Tony Lindgren, linux-wireless, Network Development,
	linux-kernel
In-Reply-To: <20161121155153.GM13735@pali>

On 21 November 2016 at 16:51, Pali Roh=C3=A1r <pali.rohar@gmail.com> wrote:
> On Friday 11 November 2016 18:20:50 Pali Roh=C3=A1r wrote:
>> Hi! I will open discussion about mac address and calibration data for
>> wl1251 wireless chip again...
>>
>> Problem: Mac address & calibration data for wl1251 chip on Nokia N900
>> are stored on second nand partition (mtd1) in special proprietary format
>> which is used only for Nokia N900 (probably on N8x0 and N9 too).
>> Wireless driver wl1251.ko cannot work without mac address and
>> calibration data.

Same problem applies to some ath9k/ath10k supported routers. Some even
carry mac address as implicit offset from ethernet mac address. As far
as I understand OpenWRT cooks cal blobs on first boot prior to loading
modules.


>> Absence of mac address cause that driver generates random mac address at
>> every kernel boot which has couple of problems (unstable identifier of
>> wireless device due to udev permanent storage rules; unpredictable
>> behaviour for dhcp mac address assignment, mac address filtering, ...).
>>
>> Currently there is no way to set (permanent) mac address for network
>> interface from userspace. And it does not make sense to implement in
>> linux kernel large parser for proprietary format of second nand
>> partition where is mac address stored only for one device -- Nokia N900.
>>
>> Driver wl1251.ko loads calibration data via request_firmware() for file
>> wl1251-nvs.bin. There are some "example" calibration file in linux-
>> firmware repository, but it is not suitable for normal usage as real
>> calibration data are per-device specific.

You could hook up a script that cooks up the cal/mac file via
modprobe's install hook, no?


Micha=C5=82

^ permalink raw reply

* Re: wl1251 & mac address & calibration data
From: Pali Rohár @ 2016-11-22 15:31 UTC (permalink / raw)
  To: Michal Kazior
  Cc: Kalle Valo, Pavel Machek, Ivaylo Dimitrov, Sebastian Reichel,
	Aaro Koskinen, Tony Lindgren, linux-wireless, Network Development,
	linux-kernel
In-Reply-To: <CA+BoTQm5yZYccMherMnmxZ0_b2PqkCWf_0nBoRLzsro-Ujz1eQ@mail.gmail.com>

On Tuesday 22 November 2016 16:22:57 Michal Kazior wrote:
> On 21 November 2016 at 16:51, Pali Rohár <pali.rohar@gmail.com> wrote:
> > On Friday 11 November 2016 18:20:50 Pali Rohár wrote:
> >> Hi! I will open discussion about mac address and calibration data for
> >> wl1251 wireless chip again...
> >>
> >> Problem: Mac address & calibration data for wl1251 chip on Nokia N900
> >> are stored on second nand partition (mtd1) in special proprietary format
> >> which is used only for Nokia N900 (probably on N8x0 and N9 too).
> >> Wireless driver wl1251.ko cannot work without mac address and
> >> calibration data.
> 
> Same problem applies to some ath9k/ath10k supported routers. Some even
> carry mac address as implicit offset from ethernet mac address. As far
> as I understand OpenWRT cooks cal blobs on first boot prior to loading
> modules.

So... wl1251 on Nokia N900 is not alone and this problem is there for
more drivers and devices. Which means we should come up with some
generic solution.

> >> Absence of mac address cause that driver generates random mac address at
> >> every kernel boot which has couple of problems (unstable identifier of
> >> wireless device due to udev permanent storage rules; unpredictable
> >> behaviour for dhcp mac address assignment, mac address filtering, ...).
> >>
> >> Currently there is no way to set (permanent) mac address for network
> >> interface from userspace. And it does not make sense to implement in
> >> linux kernel large parser for proprietary format of second nand
> >> partition where is mac address stored only for one device -- Nokia N900.
> >>
> >> Driver wl1251.ko loads calibration data via request_firmware() for file
> >> wl1251-nvs.bin. There are some "example" calibration file in linux-
> >> firmware repository, but it is not suitable for normal usage as real
> >> calibration data are per-device specific.
> 
> You could hook up a script that cooks up the cal/mac file via
> modprobe's install hook, no?

Via modprobe hook I can either pass custom module parameter or call any
other system (shell) commands.

As wl1251.ko does not accept mac_address as module parameter, such
modprobe hook does not help -- as there is absolutely no way from
userspace to set or change (permanent) mac address.

-- 
Pali Rohár
pali.rohar@gmail.com

^ permalink raw reply


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