diff mbox

[RFC] nl80211: introduce NL80211_ATTR_SCAN_EXPIRE

Message ID 200909181849.22302.hs4233@mail.mn-solutions.de (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Holger Schurig Sept. 18, 2009, 4:49 p.m. UTC
This attribute allows user-space to override or turn of the default
BSS expiration time for NL80211_CMD_GET_SCAN.

It also allows to set an expiration for NL80211_CMD_TRIGGER_SCAN. Setting
the expiration to 0 will clean the whole BSS list.

Signed-off-by: Holger Schurig <hs4233@mail.mn-solutions.de>

---

Currently, I'm using the user-space AS-IS. Maybe I should do

  export = nla_get_u32(..) * HZ

or, if we want to specify this in ms:

  export = nla_get_u32(..) * HZ / 1000

???


A simple demo patch for iw that swaps behavior (expire all BSS at scan time,
never expire at dump time) is here:

 xx iw.orig/scan.c      2009-09-18 16:28:07.000000000 +0200
 xx iw/scan.c   2009-09-18 16:45:41.000000000 +0200
 xx -102,6 +102,8 @@ static int handle_scan(struct nl80211_st
         if (have_freqs)
                 nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);

 +       NLA_PUT_U32(msg, 83 /* NL80211_ATTR_SCAN_EXPIRE */, 0);
 +
         err = 0;
   nla_put_failure:
         nlmsg_free(ssids);
 xx -871,7 +873,10 @@ static int handle_scan_dump(struct nl802

         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_bss_handler,
                   &scan_params);
 +       NLA_PUT_U32(msg, 83 /* NL80211_ATTR_SCAN_EXPIRE */, 0);
         return 0;
 +nla_put_failure:
 +       return 2;
  }

 static int handle_scan_combined(struct nl80211_state *state,

Comments

Johannes Berg Sept. 18, 2009, 5:10 p.m. UTC | #1
On Fri, 2009-09-18 at 18:49 +0200, Holger Schurig wrote:
> This attribute allows user-space to override or turn of the default
> BSS expiration time for NL80211_CMD_GET_SCAN.
> 
> It also allows to set an expiration for NL80211_CMD_TRIGGER_SCAN. Setting
> the expiration to 0 will clean the whole BSS list.

tbh, I don't really understand the need for it. changing your AP
settings doesn't seem like a use case anyone would really care about
that much.

johannes
Holger Schurig Sept. 21, 2009, 6:42 a.m. UTC | #2
> > It also allows to set an expiration for
> > NL80211_CMD_TRIGGER_SCAN. Setting the expiration to 0 will
> > clean the whole BSS list.
>
> tbh, I don't really understand the need for it. changing your
> AP settings doesn't seem like a use case anyone would really
> care about that much.

Turning of an AP is one way making the AP vanish.

Sitting into a fork-lift and driving throught a ware-house hall 
is another way to accomplish the same.

However, it's way easier for me to change the AP's setting than 
to actually leave me office :-)


/me wishes kernel developers would have more sense for real 
life :-)
Holger Schurig Sept. 21, 2009, 7:11 a.m. UTC | #3
Hmm, I think I need some more check:

NL80211_CMD_SCAN_TRIGGER is a root-only operation
NL80211_CMD_GET_SCAN is an any-user operation.

I think that a non-root user shouldn't be allowed to specify 
NL80211_ATTR_SCAN_EXPIRE that is smaller than 
IEEE80211_SCAN_RESULT_EXPIRE, right?
Johannes Berg Sept. 21, 2009, 7:15 a.m. UTC | #4
On Mon, 2009-09-21 at 08:42 +0200, Holger Schurig wrote:
> > > It also allows to set an expiration for
> > > NL80211_CMD_TRIGGER_SCAN. Setting the expiration to 0 will
> > > clean the whole BSS list.
> >
> > tbh, I don't really understand the need for it. changing your
> > AP settings doesn't seem like a use case anyone would really
> > care about that much.
> 
> Turning of an AP is one way making the AP vanish.
> 
> Sitting into a fork-lift and driving throught a ware-house hall 
> is another way to accomplish the same.

It's not actually the same, and you didn't explain that well. You care
about the disappear case, but you made it sound like you cared about the
_reappear_ case.

However, I still don't believe that you need to change anything in the
kernel, just get wpa_supplicant to handle it properly.

johannes
Holger Schurig Sept. 21, 2009, 7:46 a.m. UTC | #5
> It's not actually the same, and you didn't explain that well.
> You care about the disappear case, but you made it sound like
> you cared about the _reappear_ case.

Okay, sorry. I thought you read my other mails about 
scan-life-time and that thus the context was/is clear.


The base issue is: SCAN_TRIGGER does normally not a "clean scan", 
it normally adds entries to the BSS list or updates existing 
ones.

Entries in the BSS list are only deleted after 15 seconds.



However, in 15 seconds you can easily leave the range of AP_OLD 
and be in the range of a completely AP_NEW. But it can also be 
the case that the (now stale!) signal of AP_OLD is higher than 
the (real) signal of AP_NEW. In this case wpa_supplicant tries 
to associate to AP_OLD, which is out-of-sight. And that takes 
unneeded time.


I simple tried to mimick this scenario in the office, by 
switching off an AP (just that I didn't really switch it off, 
because the boot-times of Cisco-APs are soooooooo sloooooow).

About your "It's not actually the same": I think that my 
laboratory experiment very well shows this behavior, e.g. see my 
2nd message with subject "Life-time of scan-results?":

1253275108.958746: Trying to authenticate with 00:13:19:80:da:30 
(SSID='MNHS' freq=2412 MHz)

Bit this is the "vanished" AP_OLD. With wireshark on a second 
WLAN card I saw the attemps of mac80211 to associate to this 
now-out-of-sight AP. This takes some tries from mac80211, then a 
timeout on wpa_supplicant, than a new scan, then a new attempt. 
All of those delays completely unnecessary if there would have 
been a way to not get stale data via SCAN_DUMP.



So, clearly I have a visible problem and need to fix that.

I could fix that by making SCAN_TRIGGER always delete all stale 
(cached) entries. Then I wouldn't need NL80211_ATTR_SCAN_EXPIRE.

However, a scan because "I want to look what is around" might be 
different to a scan because "I need fresh data of APs around for 
associating". And so I thought I make that configurable.


I hope this now makes more sense.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Johannes Berg Sept. 22, 2009, 6:50 p.m. UTC | #6
On Mon, 2009-09-21 at 09:46 +0200, Holger Schurig wrote:

> I hope this now makes more sense.

It does, but I disagree with the solution. IMO we should just add a
"last seen at" timestamp to each BSS so wpa_supplicant can make the
decision which ones to look at and which ones to ignore. They'll all be
used when you don't let wpa_supplicant roam, but that doesn't really
matter much.

johannes
Dan Williams Sept. 22, 2009, 11:29 p.m. UTC | #7
On Mon, 2009-09-21 at 09:46 +0200, Holger Schurig wrote:
> > It's not actually the same, and you didn't explain that well.
> > You care about the disappear case, but you made it sound like
> > you cared about the _reappear_ case.
> 
> Okay, sorry. I thought you read my other mails about 
> scan-life-time and that thus the context was/is clear.
> 
> 
> The base issue is: SCAN_TRIGGER does normally not a "clean scan", 
> it normally adds entries to the BSS list or updates existing 
> ones.
> 
> Entries in the BSS list are only deleted after 15 seconds.

So on the supplicant side, this weekend I was discussing with Jouni
about making the supplicant *not* trigger a completely new scan when
trying to associate if the scan list was current in the past 5 or 10
seconds.  The issue here is that NM requests a scan, figures out what AP
to start using, then tells the supplicant to associate with it.  Then
the supplicant throws away any scan results it has an does a full *new*
scan before associating.  That adds about 5 seconds to each NM
connection attempt that I'd like to get rid of.

Would that interfere with your forklift case?

BTW, 10 years ago I did a forklift deployment too with pre-802.11
Aironet equipment and Netware.  Wasn't that fun to get up and running.
This was at a paper company too, and guess what huge rolls of paper do?
They absorb radio waves quite well.  Suck.  And forklifts can go *fast*.

Dan

> 
> 
> However, in 15 seconds you can easily leave the range of AP_OLD 
> and be in the range of a completely AP_NEW. But it can also be 
> the case that the (now stale!) signal of AP_OLD is higher than 
> the (real) signal of AP_NEW. In this case wpa_supplicant tries 
> to associate to AP_OLD, which is out-of-sight. And that takes 
> unneeded time.
> 
> 
> I simple tried to mimick this scenario in the office, by 
> switching off an AP (just that I didn't really switch it off, 
> because the boot-times of Cisco-APs are soooooooo sloooooow).
> 
> About your "It's not actually the same": I think that my 
> laboratory experiment very well shows this behavior, e.g. see my 
> 2nd message with subject "Life-time of scan-results?":
> 
> 1253275108.958746: Trying to authenticate with 00:13:19:80:da:30 
> (SSID='MNHS' freq=2412 MHz)
> 
> Bit this is the "vanished" AP_OLD. With wireshark on a second 
> WLAN card I saw the attemps of mac80211 to associate to this 
> now-out-of-sight AP. This takes some tries from mac80211, then a 
> timeout on wpa_supplicant, than a new scan, then a new attempt. 
> All of those delays completely unnecessary if there would have 
> been a way to not get stale data via SCAN_DUMP.
> 
> 
> 
> So, clearly I have a visible problem and need to fix that.
> 
> I could fix that by making SCAN_TRIGGER always delete all stale 
> (cached) entries. Then I wouldn't need NL80211_ATTR_SCAN_EXPIRE.
> 
> However, a scan because "I want to look what is around" might be 
> different to a scan because "I need fresh data of APs around for 
> associating". And so I thought I make that configurable.
> 
> 
> I hope this now makes more sense.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Holger Schurig Sept. 23, 2009, 7:12 a.m. UTC | #8
On Wednesday 23 September 2009 01:29:32 Dan Williams wrote:

> So on the supplicant side, this weekend I was discussing with
> Jouni about making the supplicant *not* trigger a completely
> new scan when trying to associate if the scan list was current
> in the past 5 or 10 seconds.  The issue here is that NM
> requests a scan, ... 

I currently center around a setup without NM. Okay, for the
forklift terminals (they are x86-based), NM would be feasible.
But for the handheld terminals (Intel PXA based) I'm not keen
on NM. So I basically develop a simple program that monitors
signal and triggers a scan when signal level is below some
thresshold. This program happens to be linked into
wpa_supplicant, but it can also be a standalone program.

I'm relying on wpa_supplicant's feature to monitor scan-done
events and looking if there's something a better matching BSS
in the result.



But when you take wpa_supplicant, NM and whatever, then maybe the
timestamp idea from Johannes should be used. Any application
that wants to look if it should roam can quickly get the
scan results. By the timestamp of the entries it can then
see how old the entries are. Only if entries are outdated,
it can fire up a scan.

There's just one case: if there is no BSS in the scan list.
Then any app doing a "get scan results" call wouldn't know
if the last scan is ages ago or if there is really no AP
in the vincinity, doing an immediate re-scan. This can be
harmful for battery-driven devices. So maybe a timestamp
"last scan was at timestamp XXX" besides the individual
BSS timestamps would be helpful here.

This way apps can synchronize themselfes and, even if
different apps do scanning, they can say "We don't scan
more often than every N seconds".


> BTW, 10 years ago I did a forklift deployment too with pre-802.11
> Aironet equipment and Netware.  Wasn't that fun to get up and running.
> This was at a paper company too, and guess what huge rolls of paper do?
> They absorb radio waves quite well.  Suck.  And forklifts can go *fast*.

Oh, and a wholesale company for drinks is even more demanding.
Water-based liquid has the nice property of absorbing microwaves
in the 2.4 MHz range extremely nicely, just see your next
microwave oven for a proof ...


The nice thing about this: when you have a working roaming 
(and fast-enought handoff) in a warehouse/fork-lift scenary,
then your can forget about the WLAN problem in other scenarios,
because they are way less demanding. What happens to work in
the forklift case works everywhere else.
Johannes Berg Sept. 23, 2009, 7:21 a.m. UTC | #9
On Wed, 2009-09-23 at 09:12 +0200, Holger Schurig wrote:

> There's just one case: if there is no BSS in the scan list.
> Then any app doing a "get scan results" call wouldn't know
> if the last scan is ages ago or if there is really no AP
> in the vincinity, doing an immediate re-scan. This can be
> harmful for battery-driven devices. So maybe a timestamp
> "last scan was at timestamp XXX" besides the individual
> BSS timestamps would be helpful here.
> 
> This way apps can synchronize themselfes and, even if
> different apps do scanning, they can say "We don't scan
> more often than every N seconds".

You can monitor nl80211 events for scan completion already, so this
isn't really an issue. In fact, adding a "last scan" thing would not be
a good idea since the scan might have been different, only contained a
subset of channels, etc.

johannes
Holger Schurig Sept. 23, 2009, 7:34 a.m. UTC | #10
> You can monitor nl80211 events for scan completion already, so this
> isn't really an issue. In fact, adding a "last scan" thing would not be
> a good idea since the scan might have been different, only contained a
> subset of channels, etc.

Ah, yes.
diff mbox

Patch

Index: linux-wl/net/wireless/core.h
===================================================================
--- linux-wl.orig/net/wireless/core.h	2009-09-18 14:49:42.000000000 +0200
+++ linux-wl/net/wireless/core.h	2009-09-18 17:31:05.000000000 +0200
@@ -270,7 +270,9 @@  void ieee80211_set_bitrate_flags(struct 
 void wiphy_update_regulatory(struct wiphy *wiphy,
 			     enum nl80211_reg_initiator setby);
 
-void cfg80211_bss_expire(struct cfg80211_registered_device *dev);
+#define IEEE80211_SCAN_RESULT_EXPIRE	(15 * HZ)
+
+void cfg80211_bss_expire(struct cfg80211_registered_device *dev, int expire);
 void cfg80211_bss_age(struct cfg80211_registered_device *dev,
                       unsigned long age_secs);
 
Index: linux-wl/net/wireless/nl80211.c
===================================================================
--- linux-wl.orig/net/wireless/nl80211.c	2009-09-18 14:49:42.000000000 +0200
+++ linux-wl/net/wireless/nl80211.c	2009-09-18 17:36:04.000000000 +0200
@@ -138,6 +138,7 @@  static struct nla_policy nl80211_policy[
 	[NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
 	[NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
 	[NL80211_ATTR_PID] = { .type = NLA_U32 },
+	[NL80211_ATTR_SCAN_EXPIRE] = { .type = NLA_U32 },
 };
 
 /* policy for the attributes */
@@ -2945,6 +2946,13 @@  static int nl80211_trigger_scan(struct s
 		goto out;
 	}
 
+	if (info->attrs[NL80211_ATTR_SCAN_EXPIRE]) {
+		u32 expire = nla_get_u32(info->attrs[NL80211_ATTR_SCAN_EXPIRE]);
+		spin_lock_bh(&rdev->bss_lock);
+		cfg80211_bss_expire(rdev, expire);
+		spin_unlock_bh(&rdev->bss_lock);
+	}
+
 	if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
 		n_channels = validate_scan_freqs(
 				info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
@@ -3158,11 +3166,13 @@  static int nl80211_dump_scan(struct sk_b
 	int ifidx = cb->args[0];
 	int start = cb->args[1], idx = 0;
 	int err;
+	u32 expire = IEEE80211_SCAN_RESULT_EXPIRE;
+
+	err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
+			  nl80211_fam.attrbuf, nl80211_fam.maxattr,
+			  nl80211_policy);
 
 	if (!ifidx) {
-		err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
-				  nl80211_fam.attrbuf, nl80211_fam.maxattr,
-				  nl80211_policy);
 		if (err)
 			return err;
 
@@ -3187,9 +3197,20 @@  static int nl80211_dump_scan(struct sk_b
 
 	wdev = dev->ieee80211_ptr;
 
+	/*
+	 * If expire is set (the default), expire the BSS list before
+	 * returning values. However, user-space can set a different
+	 * expire time via NL80211_ATTR_SCAN_EXPIRE. It can also set
+	 * no expire-time at all, then we skip the expiration.
+	 */
+	if (!err && nl80211_fam.attrbuf[NL80211_ATTR_SCAN_EXPIRE])
+		expire =
+		nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_SCAN_EXPIRE]);
+
 	wdev_lock(wdev);
 	spin_lock_bh(&rdev->bss_lock);
-	cfg80211_bss_expire(rdev);
+	if (expire)
+		cfg80211_bss_expire(rdev, expire);
 
 	list_for_each_entry(scan, &rdev->bss_list, list) {
 		if (++idx <= start)
Index: linux-wl/net/wireless/scan.c
===================================================================
--- linux-wl.orig/net/wireless/scan.c	2009-09-18 14:49:42.000000000 +0200
+++ linux-wl/net/wireless/scan.c	2009-09-18 17:32:08.000000000 +0200
@@ -16,8 +16,6 @@ 
 #include "nl80211.h"
 #include "wext-compat.h"
 
-#define IEEE80211_SCAN_RESULT_EXPIRE	(15 * HZ)
-
 void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
 {
 	struct cfg80211_scan_request *request;
@@ -121,7 +119,7 @@  void cfg80211_bss_age(struct cfg80211_re
 }
 
 /* must hold dev->bss_lock! */
-void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
+void cfg80211_bss_expire(struct cfg80211_registered_device *dev, int expire)
 {
 	struct cfg80211_internal_bss *bss, *tmp;
 	bool expired = false;
@@ -129,7 +127,11 @@  void cfg80211_bss_expire(struct cfg80211
 	list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
 		if (atomic_read(&bss->hold))
 			continue;
-		if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
+		/*
+		 * If expire==0, then expire all BSS from the list,
+		 * else only expire those that are older than expire.
+		 */
+		if (expire && !time_after(jiffies, bss->ts + expire))
 			continue;
 		list_del(&bss->list);
 		rb_erase(&bss->rbn, &dev->bss_tree);
@@ -970,9 +972,11 @@  static int ieee80211_scan_results(struct
 	char *current_ev = buf;
 	char *end_buf = buf + len;
 	struct cfg80211_internal_bss *bss;
+	u32 expire = IEEE80211_SCAN_RESULT_EXPIRE;
 
 	spin_lock_bh(&dev->bss_lock);
-	cfg80211_bss_expire(dev);
+	if (expire)
+		cfg80211_bss_expire(dev, expire);
 
 	list_for_each_entry(bss, &dev->bss_list, list) {
 		if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
Index: linux-wl/include/linux/nl80211.h
===================================================================
--- linux-wl.orig/include/linux/nl80211.h	2009-09-18 15:10:53.000000000 +0200
+++ linux-wl/include/linux/nl80211.h	2009-09-18 15:11:44.000000000 +0200
@@ -481,6 +481,7 @@  enum nl80211_commands {
  * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
  *	scanning and include a zero-length SSID (wildcard) for wildcard scan
  * @NL80211_ATTR_BSS: scan result BSS
+ * @NL80211_ATTR_SCAN: expire time for cached bss list
  *
  * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain
  * 	currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_*
@@ -714,6 +715,8 @@  enum nl80211_attrs {
 
 	NL80211_ATTR_PID,
 
+	NL80211_ATTR_SCAN_EXPIRE,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,