2012-05-30 16:02:23

by Victor Goldenshtein

[permalink] [raw]
Subject: [PATCH v2 1/2] nl80211/cfg80211: add scan channel times to scan command

In order to give the usermode an ability to configure
scan channel times, and as it required for the beacon
reports in the 802.11k standard.

Add to the scan command min/max channel times. Add
min/max passive channel times, since a single scan
can contain both passive and active channels due to
regulatory constraints.

Signed-off-by: Victor Goldenshtein <[email protected]>
---

v2:
New NL80211_FEATURE_SCAN_TIMES.
Move the default scan times from mac to cfg.
Handle the default scan times also for wext.

include/linux/nl80211.h | 25 +++++++++++++++++++++++++
include/net/cfg80211.h | 11 +++++++++++
net/wireless/core.h | 1 +
net/wireless/nl80211.c | 27 ++++++++++++++++++++++++++-
net/wireless/scan.c | 33 +++++++++++++++++++++++++++++++++
5 files changed, 96 insertions(+), 1 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 2540e86..6bbcdba 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1222,6 +1222,23 @@ enum nl80211_commands {
* @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds
* or 0 to disable background scan.
*
+ * @NL80211_ATTR_SCAN_MIN_CH_TIME: Minimum active scan time (in TUs),
+ * u32 attribute to setup minimum time to wait on each channel, if received
+ * at least one probe_resp/beacon during this period will continue waiting
+ * @NL80211_ATTR_SCAN_MAX_CH_TIME, otherwise will move to next channel.
+ * @NL80211_ATTR_SCAN_MAX_CH_TIME: Maximum active scan time (in TUs),
+ * u32 attribute to setup maximum time to wait on the channel.
+ * @NL80211_ATTR_SCAN_PSV_MIN_CH_TIME: Minimum passive scan time (in TUs),
+ * u32 attribute (similar to @NL80211_ATTR_SCAN_MIN_CH_TIME).
+ * @NL80211_ATTR_SCAN_PSV_MAX_CH_TIME: Maximum passive scan time (in TUs),
+ * u32 attribute (similar to @NL80211_ATTR_SCAN_MAX_CH_TIME).
+ * Note:
+ * The above channel time attributes are for the %NL80211_CMD_TRIGGER_SCAN
+ * command. The attributes are optional, the driver will use default
+ * channel time values if the attribute is not set or set to zero.
+ * If one of the min times will be greater than max, -EINVAL will be
+ * returned. For the software scan only the min times are relevant.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1473,6 +1490,11 @@ enum nl80211_attrs {

NL80211_ATTR_BG_SCAN_PERIOD,

+ NL80211_ATTR_SCAN_MIN_CH_TIME,
+ NL80211_ATTR_SCAN_MAX_CH_TIME,
+ NL80211_ATTR_SCAN_PSV_MIN_CH_TIME,
+ NL80211_ATTR_SCAN_PSV_MAX_CH_TIME,
+
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
@@ -2865,11 +2887,14 @@ enum nl80211_ap_sme_features {
* @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates.
* @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up
* the connected inactive stations in AP mode.
+ * @NL80211_FEATURE_SCAN_TIMES: This driver supports min/max scan times
+ * configuration for the %NL80211_CMD_TRIGGER_SCAN command.
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
NL80211_FEATURE_HT_IBSS = 1 << 1,
NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
+ NL80211_FEATURE_SCAN_TIMES = 1 << 3,
};

/**
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index adb2320..948cf60 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -920,6 +920,12 @@ struct cfg80211_ssid {
* @dev: the interface
* @aborted: (internal) scan request was notified as aborted
* @no_cck: used to send probe requests at non CCK rate in 2GHz band
+ * @min_ch_time: minimum time to wait on each channel for active scans
+ * @max_ch_time: maximum time to wait on each channel for active scans
+ * @min_passive_ch_time: minimum time to wait on each channel for passive scans
+ * @max_passive_ch_time: maximum time to wait on each channel for passive scans
+ * Note: If the above channel times are not set or set to zero, the default
+ * channel times will be used.
*/
struct cfg80211_scan_request {
struct cfg80211_ssid *ssids;
@@ -936,6 +942,11 @@ struct cfg80211_scan_request {
bool aborted;
bool no_cck;

+ u32 min_ch_time;
+ u32 max_ch_time;
+ u32 min_passive_ch_time;
+ u32 max_passive_ch_time;
+
/* keep last */
struct ieee80211_channel *channels[0];
};
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 3ac2dd0..de0ed36e 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -416,6 +416,7 @@ void cfg80211_sme_scan_done(struct net_device *dev);
void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
void cfg80211_sme_disassoc(struct net_device *dev,
struct cfg80211_internal_bss *bss);
+int cfg80211_trigger_scan(struct cfg80211_registered_device *rdev);
void __cfg80211_scan_done(struct work_struct *wk);
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
void __cfg80211_sched_scan_results(struct work_struct *wk);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 859bd66..d2307ad 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -206,6 +206,10 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
[NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
+ [NL80211_ATTR_SCAN_MIN_CH_TIME] = { .type = NLA_U32 },
+ [NL80211_ATTR_SCAN_MAX_CH_TIME] = { .type = NLA_U32 },
+ [NL80211_ATTR_SCAN_PSV_MIN_CH_TIME] = { .type = NLA_U32 },
+ [NL80211_ATTR_SCAN_PSV_MAX_CH_TIME] = { .type = NLA_U32 },
};

/* policy for the key attributes */
@@ -3884,6 +3888,27 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
request->ie_len);
}

+ if (info->attrs[NL80211_ATTR_SCAN_MIN_CH_TIME]) {
+ request->min_ch_time =
+ nla_get_u32(info->attrs[NL80211_ATTR_SCAN_MIN_CH_TIME]);
+ }
+ if (info->attrs[NL80211_ATTR_SCAN_MAX_CH_TIME]) {
+ request->max_ch_time =
+ nla_get_u32(info->attrs[NL80211_ATTR_SCAN_MAX_CH_TIME]);
+ if (request->min_ch_time > request->max_ch_time)
+ return -EINVAL;
+ }
+ if (info->attrs[NL80211_ATTR_SCAN_PSV_MIN_CH_TIME]) {
+ request->min_passive_ch_time =
+ nla_get_u32(info->attrs[NL80211_ATTR_SCAN_PSV_MIN_CH_TIME]);
+ }
+ if (info->attrs[NL80211_ATTR_SCAN_PSV_MAX_CH_TIME]) {
+ request->max_passive_ch_time =
+ nla_get_u32(info->attrs[NL80211_ATTR_SCAN_PSV_MAX_CH_TIME]);
+ if (request->min_passive_ch_time > request->max_passive_ch_time)
+ return -EINVAL;
+ }
+
for (i = 0; i < IEEE80211_NUM_BANDS; i++)
if (wiphy->bands[i])
request->rates[i] =
@@ -3915,7 +3940,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
request->wiphy = &rdev->wiphy;

rdev->scan_req = request;
- err = rdev->ops->scan(&rdev->wiphy, dev, request);
+ err = cfg80211_trigger_scan(rdev);

if (!err) {
nl80211_send_scan_start(rdev, dev);
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 9dee87c..03b8b3c 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -19,6 +19,27 @@
#include "wext-compat.h"

#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)
+#define IEEE80211_CHANNEL_TIME (HZ / 33)
+#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 8)
+
+int cfg80211_trigger_scan(struct cfg80211_registered_device *rdev)
+{
+ struct cfg80211_scan_request *request;
+
+ ASSERT_RDEV_LOCK(rdev);
+
+ request = rdev->scan_req;
+
+ if (!request)
+ return -EINVAL;
+
+ if (!request->min_passive_ch_time)
+ request->min_passive_ch_time = IEEE80211_PASSIVE_CHANNEL_TIME;
+ if (!request->min_ch_time)
+ request->min_ch_time = IEEE80211_CHANNEL_TIME;
+
+ return rdev->ops->scan(&rdev->wiphy, request->dev, request);
+}

void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
{
@@ -1023,6 +1044,18 @@ int cfg80211_wext_siwscan(struct net_device *dev,
if (wiphy->bands[i])
creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;

+ if (wreq->min_channel_time) {
+ creq->min_ch_time = wreq->min_channel_time;
+ if (wreq->scan_type == IW_SCAN_TYPE_ACTIVE)
+ creq->min_passive_ch_time =
+ IEEE80211_PASSIVE_CHANNEL_TIME;
+ else
+ creq->min_passive_ch_time = wreq->min_channel_time;
+ } else {
+ creq->min_ch_time = IEEE80211_CHANNEL_TIME;
+ creq->min_passive_ch_time = IEEE80211_PASSIVE_CHANNEL_TIME;
+ }
+
rdev->scan_req = creq;
err = rdev->ops->scan(wiphy, dev, creq);
if (err) {
--
1.7.5.4



2012-05-30 16:31:59

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] nl80211/cfg80211: add scan channel times to scan command

On Wed, 2012-05-30 at 18:59 +0300, Victor Goldenshtein wrote:

> + if (info->attrs[NL80211_ATTR_SCAN_MIN_CH_TIME]) {
> + request->min_ch_time =
> + nla_get_u32(info->attrs[NL80211_ATTR_SCAN_MIN_CH_TIME]);
> + }
> + if (info->attrs[NL80211_ATTR_SCAN_MAX_CH_TIME]) {
> + request->max_ch_time =
> + nla_get_u32(info->attrs[NL80211_ATTR_SCAN_MAX_CH_TIME]);
> + if (request->min_ch_time > request->max_ch_time)
> + return -EINVAL;
> + }
> + if (info->attrs[NL80211_ATTR_SCAN_PSV_MIN_CH_TIME]) {
> + request->min_passive_ch_time =
> + nla_get_u32(info->attrs[NL80211_ATTR_SCAN_PSV_MIN_CH_TIME]);
> + }
> + if (info->attrs[NL80211_ATTR_SCAN_PSV_MAX_CH_TIME]) {
> + request->max_passive_ch_time =
> + nla_get_u32(info->attrs[NL80211_ATTR_SCAN_PSV_MAX_CH_TIME]);
> + if (request->min_passive_ch_time > request->max_passive_ch_time)
> + return -EINVAL;
> + }

All of this should probably reject 0 values since they're not valid and
will be overridden -- but to get defaults you can just as well leave it
out completely.

Also, I think you should be forced to specify both min and max if you're
going to specify any at all, because otherwise you can specify a max
that is smaller than the default min and get things completely confused.

johannes


2012-05-30 16:02:25

by Victor Goldenshtein

[permalink] [raw]
Subject: [PATCH v2 2/2] mac80211: handle channel times in scan command

Use the user scan times if those were set, otherwise
use the default values.

This patch handles both hw_scan and non-offload scan.

Signed-off-by: Victor Goldenshtein <[email protected]>
---
net/mac80211/scan.c | 30 +++++++++++++++++++-----------
1 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 8282284..50d3695 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -26,8 +26,6 @@
#include "mesh.h"

#define IEEE80211_PROBE_DELAY (HZ / 33)
-#define IEEE80211_CHANNEL_TIME (HZ / 33)
-#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 8)

static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
{
@@ -421,7 +419,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
* After sending probe requests, wait for probe responses
* on the channel.
*/
- *next_delay = IEEE80211_CHANNEL_TIME;
+ *next_delay = local->scan_req->min_ch_time;
local->next_scan_state = SCAN_DECISION;
}

@@ -456,6 +454,13 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,

local->hw_scan_req->ssids = req->ssids;
local->hw_scan_req->n_ssids = req->n_ssids;
+ local->hw_scan_req->max_ch_time = req->max_ch_time;
+ local->hw_scan_req->min_ch_time = req->min_ch_time;
+ local->hw_scan_req->max_passive_ch_time =
+ req->max_passive_ch_time;
+ local->hw_scan_req->min_passive_ch_time =
+ req->min_passive_ch_time;
+
ies = (u8 *)local->hw_scan_req +
sizeof(*local->hw_scan_req) +
req->n_channels * sizeof(req->channels[0]);
@@ -502,10 +507,10 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
if ((req->channels[0]->flags &
IEEE80211_CHAN_PASSIVE_SCAN) ||
!local->scan_req->n_ssids) {
- next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+ next_delay = local->scan_req->min_passive_ch_time;
} else {
ieee80211_scan_state_send_probe(local, &next_delay);
- next_delay = IEEE80211_CHANNEL_TIME;
+ next_delay = local->scan_req->min_ch_time;
}

/* Now, just wait a bit and we are all done! */
@@ -540,15 +545,16 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
}

static unsigned long
-ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
+ieee80211_scan_get_channel_time(struct cfg80211_scan_request *scan_req,
+ struct ieee80211_channel *chan)
{
/*
* TODO: channel switching also consumes quite some time,
* add that delay as well to get a better estimation
*/
if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
- return IEEE80211_PASSIVE_CHANNEL_TIME;
- return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
+ return scan_req->min_passive_ch_time;
+ return IEEE80211_PROBE_DELAY + scan_req->min_ch_time;
}

static void ieee80211_scan_state_decision(struct ieee80211_local *local,
@@ -609,12 +615,14 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
*/

bad_latency = time_after(jiffies +
- ieee80211_scan_get_channel_time(next_chan),
+ ieee80211_scan_get_channel_time(local->scan_req,
+ next_chan),
local->leave_oper_channel_time +
usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY)));

listen_int_exceeded = time_after(jiffies +
- ieee80211_scan_get_channel_time(next_chan),
+ ieee80211_scan_get_channel_time(local->scan_req,
+ next_chan),
local->leave_oper_channel_time +
usecs_to_jiffies(min_beacon_int * 1024) *
local->hw.conf.listen_interval);
@@ -662,7 +670,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
*/
if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
!local->scan_req->n_ssids) {
- *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+ *next_delay = local->scan_req->min_passive_ch_time;
local->next_scan_state = SCAN_DECISION;
return;
}
--
1.7.5.4


2012-05-30 17:30:56

by Victor Goldenshtein

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] nl80211/cfg80211: add scan channel times to scan command

On Wed, May 30, 2012 at 7:33 PM, Johannes Berg
<[email protected]> wrote:
> On Wed, 2012-05-30 at 18:59 +0300, Victor Goldenshtein wrote:
>
>> ?#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)
>> +#define ? ? ?IEEE80211_CHANNEL_TIME ? ? ? ? ?(HZ / 33)
>> +#define ? ? ?IEEE80211_PASSIVE_CHANNEL_TIME ?(HZ / 8)
>
> And as you just heard on IRC, this is bogus since the units are supposed
> to be TU, not jiffies (which isn't a valid unit to use in a userspace
> API anyway since it's not even a "constant" unit)
>

will define the default scan times in TU as:

+#define ? ? ?IEEE80211_CHANNEL_TIME_TU ? ? ? ? ? (1024 / 33)
+#define ? ? ?IEEE80211_PASSIVE_CHANNEL_TIME_TU ?(1024 / 8)

and will convert them back to jiffies in the software scan.

--
Thanks,
Victor.

2012-05-30 16:33:15

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] nl80211/cfg80211: add scan channel times to scan command

On Wed, 2012-05-30 at 18:59 +0300, Victor Goldenshtein wrote:

> #define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)
> +#define IEEE80211_CHANNEL_TIME (HZ / 33)
> +#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 8)

And as you just heard on IRC, this is bogus since the units are supposed
to be TU, not jiffies (which isn't a valid unit to use in a userspace
API anyway since it's not even a "constant" unit)

johannes