Skip to contentSkip to conversation

mac80211: Filter scan results

RFC PATCH In review Samuel Ortiz 7 participants 24 messages Feb 4, 2009 – Feb 5, 2009 mac80211

lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 mac80211: Filter scan results

From: Samuel Ortiz <[email protected]>

In very dense environment, the scan result buffer can get really large, mostly due to the addition of proprietary IEs. iwlist fails, typically warning about:
"print_scanning_info: Allocation failed". wpa_supplicant fails as well, after reallocating the scan result buffer several times, up to 132 Kbytes:
[snip]
Scan results did not fit - trying larger buffer (131072 bytes) ioctl[SIOCGIWSCAN]: Argument list too long

By adding a mac80211 module parameter, we can filter the scan results and keep only the ones userspace currently worries about, i.e. WPA1, WPA2, WMM and WPS.

To activate this feature, 1 has to be written to /sys/module/mac80211/parameters/ieee80211_scan_ie_filter

---
 net/mac80211/ieee80211_i.h |    1 
 net/mac80211/scan.c        |   65 ++++++++++++++++++++++++++++++---------------
 net/mac80211/util.c        |   40 +++++++++++++++++++++++++++
 3 files changed, 85 insertions(+), 21 deletions(-)
net/mac80211/scan.c +44 -21
Index: wireless-testing/net/mac80211/scan.c
===================================================================
@@ -31,6 +31,11 @@
 #define IEEE80211_CHANNEL_TIME (HZ / 33)
 #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)
 
+static int ieee80211_scan_ie_filter;
+module_param(ieee80211_scan_ie_filter, bool, 0644);
+MODULE_PARM_DESC(ieee80211_scan_ie_filter,
+		 "Filter IEs from scan results");
+
 void ieee80211_rx_bss_list_init(struct ieee80211_local *local)
 {
 	spin_lock_init(&local->bss_lock);
@@ -725,33 +730,51 @@ static void ieee80211_scan_add_ies(struc
 	if (bss == NULL || bss->ies == NULL)
 		return;
 
-	/*
-	 * If needed, fragment the IEs buffer (at IE boundaries) into short
-	 * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
-	 */
 	pos = bss->ies;
 	end = pos + bss->ies_len;
 
-	while (end - pos > IW_GENERIC_IE_MAX) {
-		next = pos + 2 + pos[1];
-		while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
-			next = next + 2 + next[1];
+	if (ieee80211_scan_ie_filter) {
+		while (pos - end) {
+			next = pos + 2 + pos[1];
+			if (ieee80211_filter_ie(pos)) {
+				memset(&iwe, 0, sizeof(iwe));
+				iwe.cmd = IWEVGENIE;
+				iwe.u.data.length = next - pos;
+				*current_ev =
+					iwe_stream_add_point(info, *current_ev,
+							     end_buf, &iwe,
+							     pos);
+			}
+			pos = next;
+		}
+	} else {
+		/*
+		 * If needed, fragment the IEs buffer (at IE boundaries) into
+		 * short enough fragments to fit into IW_GENERIC_IE_MAX octet
+		 * messages.
+		 */
+
+		while (end - pos > IW_GENERIC_IE_MAX) {
+			next = pos + 2 + pos[1];
+			while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
+				next = next + 2 + next[1];
 
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = IWEVGENIE;
-		iwe.u.data.length = next - pos;
-		*current_ev = iwe_stream_add_point(info, *current_ev,
-						   end_buf, &iwe, pos);
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVGENIE;
+			iwe.u.data.length = next - pos;
+			*current_ev = iwe_stream_add_point(info, *current_ev,
+							   end_buf, &iwe, pos);
 
-		pos = next;
-	}
+			pos = next;
+		}
 
-	if (end > pos) {
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = IWEVGENIE;
-		iwe.u.data.length = end - pos;
-		*current_ev = iwe_stream_add_point(info, *current_ev,
-						   end_buf, &iwe, pos);
+		if (end > pos) {
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVGENIE;
+			iwe.u.data.length = end - pos;
+			*current_ev = iwe_stream_add_point(info, *current_ev,
+							   end_buf, &iwe, pos);
+		}
 	}
 }
 
net/mac80211/util.c +40 -0
Index: wireless-testing/net/mac80211/util.c
===================================================================
@@ -675,6 +675,46 @@ void ieee802_11_parse_elems(u8 *start, s
 	}
 }
 
+/*
+ * ieee80211_filter_ie() tries to keep only the relevant IEs for
+ * userspace (mostly hostap code).
+ */
+int ieee80211_filter_ie(u8 *ie)
+{
+	u8 id, ie_len, *pos;
+	u8 microsoft_oui[4] = {0x00, 0x50, 0xf2};
+	u8 wpa2_oui[3] = {0x00, 0x0f, 0xac};
+
+	pos = ie;
+	id = *pos++;
+	ie_len = *pos++;
+
+	switch (id) {
+	case WLAN_EID_RSN:
+		/* WPA2 */
+		if (ie_len >= 3 &&
+		    !memcmp(pos, wpa2_oui, 3))
+			return 1;
+
+		return 0;
+
+	case WLAN_EID_VENDOR_SPECIFIC:
+		/* We're trying to catch WPA1, WMM and WPS IEs. */
+		if (ie_len >= 3 &&
+		    !memcmp(pos, microsoft_oui, 3)) {
+			if ((pos[3] == 1) || /* WPA1 */
+			    (pos[3] == 2) || /* WMM */
+			    (pos[3] == 4))   /* WPS */
+				return 1;
+		}
+
+		return 0;
+
+	default:
+		return 0;
+	}
+}
+
 void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_local *local = sdata->local;
net/mac80211/ieee80211_i.h +1 -0
Index: wireless-testing/net/mac80211/ieee80211_i.h
===================================================================
@@ -1028,6 +1028,7 @@ void ieee80211_tx_skb(struct ieee80211_s
 		      int encrypt);
 void ieee802_11_parse_elems(u8 *start, size_t len,
 			    struct ieee802_11_elems *elems);
+int ieee80211_filter_ie(u8 *ie);
 int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq);
 u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
 			      enum ieee80211_band band);
Signature · 2 lines
Intel Open Source Technology Centre
http://oss.intel.com/
maintainer
#1 lore raw
Quoted 10 lines · Samuel Ortiz

From: Samuel Ortiz <[email protected]>

In very dense environment, the scan result buffer can get really large, mostly due to the addition of proprietary IEs. iwlist fails, typically warning about:
"print_scanning_info: Allocation failed". wpa_supplicant fails as well, after reallocating the scan result buffer several times, up to 132 Kbytes:
[snip]
Scan results did not fit - trying larger buffer (131072 bytes) ioctl[SIOCGIWSCAN]: Argument list too long

Quoted 5 lines

By adding a mac80211 module parameter, we can filter the scan results and keep only the ones userspace currently worries about, i.e. WPA1, WPA2, WMM and WPS.

To activate this feature, 1 has to be written to /sys/module/mac80211/parameters/ieee80211_scan_ie_filter

Module parameter, hard-coded filter, just to work around wext crap. Eww. NACK.

Go for
http://johannes.sipsolutions.net/patches/kernel/all/LATEST/028-cfg80211-scan.patch
instead.

johannes

#2 lore raw

Hi Johannes,

Quoted 8 lines
Quoted 8 lines

In very dense environment, the scan result buffer can get really large, mostly due to the addition of proprietary IEs. iwlist fails, typically warning about:
"print_scanning_info: Allocation failed". wpa_supplicant fails as well, after reallocating the scan result buffer several times, up to 132 Kbytes:
[snip]
Scan results did not fit - trying larger buffer (131072 bytes) ioctl[SIOCGIWSCAN]: Argument list too long

Quoted 8 lines
Quoted 5 lines

By adding a mac80211 module parameter, we can filter the scan results and keep only the ones userspace currently worries about, i.e. WPA1, WPA2, WMM and WPS.

To activate this feature, 1 has to be written to /sys/module/mac80211/parameters/ieee80211_scan_ie_filter

Module parameter, hard-coded filter, just to work around wext crap. Eww. NACK.

we are perfectly aware that this is ugly and trust me, that nobody of us wants to do it. However we do have these setups and they happen in real life. I have been in a couple of locations where I ran into this problem and in that cases there is no way for me to establish any kind of WiFi connection at all, because the buffers are just too small. And that is with a laptop. Then just think about a mobile phone running mac80211 where the memory is limited.

So WEXT is crap and everybody agrees, but until we can use cfg80211 for scanning, we need something to make this work. So if this patch is not acceptable, then do we get scanning support via cfg80211 for 2.6.30? You were always marking your patches as development/RFC.

Quoted 2 lines

Go for
http://johannes.sipsolutions.net/patches/kernel/all/LATEST/028-cfg80211-scan.patch

Return a 404 btw.

Regards

Marcel

#3 lore raw
Quoted 27 lines · Marcel Holtmann

Hi Johannes,

Quoted 8 lines
Quoted 8 lines

In very dense environment, the scan result buffer can get really large, mostly due to the addition of proprietary IEs. iwlist fails, typically warning about:
"print_scanning_info: Allocation failed". wpa_supplicant fails as well, after reallocating the scan result buffer several times, up to 132 Kbytes:
[snip]
Scan results did not fit - trying larger buffer (131072 bytes) ioctl[SIOCGIWSCAN]: Argument list too long

Quoted 8 lines
Quoted 5 lines

By adding a mac80211 module parameter, we can filter the scan results and keep only the ones userspace currently worries about, i.e. WPA1, WPA2, WMM and WPS.

To activate this feature, 1 has to be written to /sys/module/mac80211/parameters/ieee80211_scan_ie_filter

Module parameter, hard-coded filter, just to work around wext crap. Eww. NACK.

we are perfectly aware that this is ugly and trust me, that nobody of us wants to do it. However we do have these setups and they happen in real life. I have been in a couple of locations where I ran into this problem and in that cases there is no way for me to establish any kind of WiFi connection at all, because the buffers are just too small. And that is with a laptop. Then just think about a mobile phone running mac80211 where the memory is limited.

Quoted 2 lines

So WEXT is crap and everybody agrees, but until we can use cfg80211 for scanning, we need something to make this work. So if this patch is not

No. This does not go into the kernel. Help make cfg80211 work for you, and you're perfectly free to patch your kernels as you see fit. You can certainly backport cfg80211 scanning bits to whatever kernels you care about, just the same as you'd backport this hack to whatever kernels you care about.

Dan

#4 lore raw

Hi Dan,

Quoted 25 lines
Quoted 25 lines
Quoted 8 lines
Quoted 8 lines

In very dense environment, the scan result buffer can get really large, mostly due to the addition of proprietary IEs. iwlist fails, typically warning about:
"print_scanning_info: Allocation failed". wpa_supplicant fails as well, after reallocating the scan result buffer several times, up to 132 Kbytes:
[snip]
Scan results did not fit - trying larger buffer (131072 bytes) ioctl[SIOCGIWSCAN]: Argument list too long

Quoted 8 lines
Quoted 5 lines

By adding a mac80211 module parameter, we can filter the scan results and keep only the ones userspace currently worries about, i.e. WPA1, WPA2, WMM and WPS.

To activate this feature, 1 has to be written to /sys/module/mac80211/parameters/ieee80211_scan_ie_filter

Module parameter, hard-coded filter, just to work around wext crap. Eww. NACK.

we are perfectly aware that this is ugly and trust me, that nobody of us wants to do it. However we do have these setups and they happen in real life. I have been in a couple of locations where I ran into this problem and in that cases there is no way for me to establish any kind of WiFi connection at all, because the buffers are just too small. And that is with a laptop. Then just think about a mobile phone running mac80211 where the memory is limited.

Quoted 8 lines
Quoted 2 lines

So WEXT is crap and everybody agrees, but until we can use cfg80211 for scanning, we need something to make this work. So if this patch is not

No. This does not go into the kernel. Help make cfg80211 work for you, and you're perfectly free to patch your kernels as you see fit. You can certainly backport cfg80211 scanning bits to whatever kernels you care about, just the same as you'd backport this hack to whatever kernels you care about.

this is not a matter of backporting. The matter is that neither WEXT nor cfg80211 allow scanning in dense RF environment. We are more than happy to actually use cfg80211, but I have never seen any final patch for adding scanning support. All of them were more or less work-in-progress.

Regards

Marcel

maintainer
#5 lore raw
In reply to Marcel Holtmann
Quoted 11 lines
Quoted 3 lines

Module parameter, hard-coded filter, just to work around wext crap. Eww. NACK.

we are perfectly aware that this is ugly and trust me, that nobody of us wants to do it. However we do have these setups and they happen in real life. I have been in a couple of locations where I ran into this problem and in that cases there is no way for me to establish any kind of WiFi connection at all, because the buffers are just too small. And that is with a laptop. Then just think about a mobile phone running mac80211 where the memory is limited.

That's a straw-man. Your applications are _artificially_ limiting the wext buffer size, to something well below your mobile phone's memory.

Quoted 4 lines

So WEXT is crap and everybody agrees, but until we can use cfg80211 for scanning, we need something to make this work. So if this patch is not acceptable, then do we get scanning support via cfg80211 for 2.6.30? You were always marking your patches as development/RFC.

This patch is _certainly_ not acceptable. You know that just as well as I do. And of course you can get scanning with cfg80211/nl80211 in 2.6.30. You just have to help make it work. The patch below has one major flaw: it keeps all BSSes in a doubly-linked list. That gives horrible lookup behaviour. So I set about to fix it:

http://johannes.sipsolutions.net/patches/kernel/all/LATEST/029-b%2btree.patch
http://johannes.sipsolutions.net/patches/kernel/all/LATEST/030-cfg80211-scan-btree.patch

but the b+tree was pretty much rejected, and I don't currently have time to spend on investigating other types of trees (rbtrees, ...) or hash tables. Without that, it's going to suck, especially on the embedded devices you mention.

Quoted 4 lines
Quoted 2 lines

Go for
http://johannes.sipsolutions.net/patches/kernel/all/LATEST/028-cfg80211-scan.patch

Return a 404 btw.

Yeah, so I rebased and it's now at
http://johannes.sipsolutions.net/patches/kernel/all/LATEST/024-cfg80211-scan.patch

johannes

#6 lore raw
In reply to Samuel Ortiz
Quoted 10 lines · Samuel Ortiz

From: Samuel Ortiz <[email protected]>

In very dense environment, the scan result buffer can get really large, mostly due to the addition of proprietary IEs. iwlist fails, typically warning about:
"print_scanning_info: Allocation failed". wpa_supplicant fails as well, after reallocating the scan result buffer several times, up to 132 Kbytes:
[snip]
Scan results did not fit - trying larger buffer (131072 bytes) ioctl[SIOCGIWSCAN]: Argument list too long

Quoted 5 lines

By adding a mac80211 module parameter, we can filter the scan results and keep only the ones userspace currently worries about, i.e. WPA1, WPA2, WMM and WPS.

To activate this feature, 1 has to be written to /sys/module/mac80211/parameters/ieee80211_scan_ie_filter

NAK. Use cfg80211. Module parameters are the wrong way to work around API limitations; the API gets fixed or replaced instead. Furthermore, the stack/drivers should *NOT* be filtering scan results at all. That's the job of the userspace program requesting the results; otherwise passive listeners will get only filtered results, and not the complete scan list.

Dan

Quoted 159 lines
---
 net/mac80211/ieee80211_i.h |    1 
 net/mac80211/scan.c        |   65 ++++++++++++++++++++++++++++++---------------
 net/mac80211/util.c        |   40 +++++++++++++++++++++++++++
 3 files changed, 85 insertions(+), 21 deletions(-)

Index: wireless-testing/net/mac80211/scan.c
===================================================================

net/mac80211/scan.c +44 -21
@@ -31,6 +31,11 @@
 #define IEEE80211_CHANNEL_TIME (HZ / 33)
 #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)
 
+static int ieee80211_scan_ie_filter;
+module_param(ieee80211_scan_ie_filter, bool, 0644);
+MODULE_PARM_DESC(ieee80211_scan_ie_filter,
+		 "Filter IEs from scan results");
+
 void ieee80211_rx_bss_list_init(struct ieee80211_local *local)
 {
 	spin_lock_init(&local->bss_lock);
@@ -725,33 +730,51 @@ static void ieee80211_scan_add_ies(struc
 	if (bss == NULL || bss->ies == NULL)
 		return;
 
-	/*
-	 * If needed, fragment the IEs buffer (at IE boundaries) into short
-	 * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
-	 */
 	pos = bss->ies;
 	end = pos + bss->ies_len;
 
-	while (end - pos > IW_GENERIC_IE_MAX) {
-		next = pos + 2 + pos[1];
-		while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
-			next = next + 2 + next[1];
+	if (ieee80211_scan_ie_filter) {
+		while (pos - end) {
+			next = pos + 2 + pos[1];
+			if (ieee80211_filter_ie(pos)) {
+				memset(&iwe, 0, sizeof(iwe));
+				iwe.cmd = IWEVGENIE;
+				iwe.u.data.length = next - pos;
+				*current_ev =
+					iwe_stream_add_point(info, *current_ev,
+							     end_buf, &iwe,
+							     pos);
+			}
+			pos = next;
+		}
+	} else {
+		/*
+		 * If needed, fragment the IEs buffer (at IE boundaries) into
+		 * short enough fragments to fit into IW_GENERIC_IE_MAX octet
+		 * messages.
+		 */
+
+		while (end - pos > IW_GENERIC_IE_MAX) {
+			next = pos + 2 + pos[1];
+			while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
+				next = next + 2 + next[1];
 
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = IWEVGENIE;
-		iwe.u.data.length = next - pos;
-		*current_ev = iwe_stream_add_point(info, *current_ev,
-						   end_buf, &iwe, pos);
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVGENIE;
+			iwe.u.data.length = next - pos;
+			*current_ev = iwe_stream_add_point(info, *current_ev,
+							   end_buf, &iwe, pos);
 
-		pos = next;
-	}
+			pos = next;
+		}
 
-	if (end > pos) {
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = IWEVGENIE;
-		iwe.u.data.length = end - pos;
-		*current_ev = iwe_stream_add_point(info, *current_ev,
-						   end_buf, &iwe, pos);
+		if (end > pos) {
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVGENIE;
+			iwe.u.data.length = end - pos;
+			*current_ev = iwe_stream_add_point(info, *current_ev,
+							   end_buf, &iwe, pos);
+		}
 	}
 }
 

Index: wireless-testing/net/mac80211/util.c
===================================================================

net/mac80211/util.c +40 -0
@@ -675,6 +675,46 @@ void ieee802_11_parse_elems(u8 *start, s
 	}
 }
 
+/*
+ * ieee80211_filter_ie() tries to keep only the relevant IEs for
+ * userspace (mostly hostap code).
+ */
+int ieee80211_filter_ie(u8 *ie)
+{
+	u8 id, ie_len, *pos;
+	u8 microsoft_oui[4] = {0x00, 0x50, 0xf2};
+	u8 wpa2_oui[3] = {0x00, 0x0f, 0xac};
+
+	pos = ie;
+	id = *pos++;
+	ie_len = *pos++;
+
+	switch (id) {
+	case WLAN_EID_RSN:
+		/* WPA2 */
+		if (ie_len >= 3 &&
+		    !memcmp(pos, wpa2_oui, 3))
+			return 1;
+
+		return 0;
+
+	case WLAN_EID_VENDOR_SPECIFIC:
+		/* We're trying to catch WPA1, WMM and WPS IEs. */
+		if (ie_len >= 3 &&
+		    !memcmp(pos, microsoft_oui, 3)) {
+			if ((pos[3] == 1) || /* WPA1 */
+			    (pos[3] == 2) || /* WMM */
+			    (pos[3] == 4))   /* WPS */
+				return 1;
+		}
+
+		return 0;
+
+	default:
+		return 0;
+	}
+}
+
 void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_local *local = sdata->local;

Index: wireless-testing/net/mac80211/ieee80211_i.h
===================================================================

net/mac80211/ieee80211_i.h +1 -0
@@ -1028,6 +1028,7 @@ void ieee80211_tx_skb(struct ieee80211_s
 		      int encrypt);
 void ieee802_11_parse_elems(u8 *start, size_t len,
 			    struct ieee802_11_elems *elems);
+int ieee80211_filter_ie(u8 *ie);
 int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq);
 u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
 			      enum ieee80211_band band);
#7 lore raw

Hi Dan,

Quoted 14 lines
Quoted 8 lines

In very dense environment, the scan result buffer can get really large, mostly due to the addition of proprietary IEs. iwlist fails, typically warning about:
"print_scanning_info: Allocation failed". wpa_supplicant fails as well, after reallocating the scan result buffer several times, up to 132 Kbytes:
[snip]
Scan results did not fit - trying larger buffer (131072 bytes) ioctl[SIOCGIWSCAN]: Argument list too long

Quoted 5 lines

By adding a mac80211 module parameter, we can filter the scan results and keep only the ones userspace currently worries about, i.e. WPA1, WPA2, WMM and WPS.

To activate this feature, 1 has to be written to /sys/module/mac80211/parameters/ieee80211_scan_ie_filter

Quoted 6 lines

NAK. Use cfg80211. Module parameters are the wrong way to work around API limitations; the API gets fixed or replaced instead. Furthermore, the stack/drivers should *NOT* be filtering scan results at all. That's the job of the userspace program requesting the results; otherwise passive listeners will get only filtered results, and not the complete scan list.

yes, yes and yes, but reality is a little bit different here. You are not able to get the results out of the kernel because WEXT is just braindead.

Regards

Marcel

#8 lore raw
Quoted 23 lines · Marcel Holtmann

Hi Dan,

Quoted 14 lines
Quoted 8 lines

In very dense environment, the scan result buffer can get really large, mostly due to the addition of proprietary IEs. iwlist fails, typically warning about:
"print_scanning_info: Allocation failed". wpa_supplicant fails as well, after reallocating the scan result buffer several times, up to 132 Kbytes:
[snip]
Scan results did not fit - trying larger buffer (131072 bytes) ioctl[SIOCGIWSCAN]: Argument list too long

Quoted 5 lines

By adding a mac80211 module parameter, we can filter the scan results and keep only the ones userspace currently worries about, i.e. WPA1, WPA2, WMM and WPS.

To activate this feature, 1 has to be written to /sys/module/mac80211/parameters/ieee80211_scan_ie_filter

Quoted 6 lines

NAK. Use cfg80211. Module parameters are the wrong way to work around API limitations; the API gets fixed or replaced instead. Furthermore, the stack/drivers should *NOT* be filtering scan results at all. That's the job of the userspace program requesting the results; otherwise passive listeners will get only filtered results, and not the complete scan list.

Quoted 3 lines

yes, yes and yes, but reality is a little bit different here. You are not able to get the results out of the kernel because WEXT is just braindead.

This hack is waaay beyond the realm of acceptable. Fix cfg80211, and backport it to the kernels you care about since you'd be doing the same backporting for this hack.

Dan

#9 lore raw
In reply to Samuel Ortiz
Quoted 10 lines · Samuel Ortiz

From: Samuel Ortiz <[email protected]>

In very dense environment, the scan result buffer can get really large, mostly due to the addition of proprietary IEs. iwlist fails, typically warning about:
"print_scanning_info: Allocation failed". wpa_supplicant fails as well, after reallocating the scan result buffer several times, up to 132 Kbytes:
[snip]
Scan results did not fit - trying larger buffer (131072 bytes) ioctl[SIOCGIWSCAN]: Argument list too long

Quoted 2 lines

By adding a mac80211 module parameter, we can filter the scan results and keep only the ones userspace currently worries about, i.e. WPA1, WPA2, WMM and WPS.

A somewhat more acceptable, but still unacceptable hack would be to figure out when the returned scan results buffer would be too large, and automatically filter the IEs when it would be to large.

The module parameter is the largest dealbreaker here.

Dan

Quoted 162 lines

To activate this feature, 1 has to be written to /sys/module/mac80211/parameters/ieee80211_scan_ie_filter

---
 net/mac80211/ieee80211_i.h |    1 
 net/mac80211/scan.c        |   65 ++++++++++++++++++++++++++++++---------------
 net/mac80211/util.c        |   40 +++++++++++++++++++++++++++
 3 files changed, 85 insertions(+), 21 deletions(-)

Index: wireless-testing/net/mac80211/scan.c
===================================================================

net/mac80211/scan.c +44 -21
@@ -31,6 +31,11 @@
 #define IEEE80211_CHANNEL_TIME (HZ / 33)
 #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)
 
+static int ieee80211_scan_ie_filter;
+module_param(ieee80211_scan_ie_filter, bool, 0644);
+MODULE_PARM_DESC(ieee80211_scan_ie_filter,
+		 "Filter IEs from scan results");
+
 void ieee80211_rx_bss_list_init(struct ieee80211_local *local)
 {
 	spin_lock_init(&local->bss_lock);
@@ -725,33 +730,51 @@ static void ieee80211_scan_add_ies(struc
 	if (bss == NULL || bss->ies == NULL)
 		return;
 
-	/*
-	 * If needed, fragment the IEs buffer (at IE boundaries) into short
-	 * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
-	 */
 	pos = bss->ies;
 	end = pos + bss->ies_len;
 
-	while (end - pos > IW_GENERIC_IE_MAX) {
-		next = pos + 2 + pos[1];
-		while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
-			next = next + 2 + next[1];
+	if (ieee80211_scan_ie_filter) {
+		while (pos - end) {
+			next = pos + 2 + pos[1];
+			if (ieee80211_filter_ie(pos)) {
+				memset(&iwe, 0, sizeof(iwe));
+				iwe.cmd = IWEVGENIE;
+				iwe.u.data.length = next - pos;
+				*current_ev =
+					iwe_stream_add_point(info, *current_ev,
+							     end_buf, &iwe,
+							     pos);
+			}
+			pos = next;
+		}
+	} else {
+		/*
+		 * If needed, fragment the IEs buffer (at IE boundaries) into
+		 * short enough fragments to fit into IW_GENERIC_IE_MAX octet
+		 * messages.
+		 */
+
+		while (end - pos > IW_GENERIC_IE_MAX) {
+			next = pos + 2 + pos[1];
+			while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
+				next = next + 2 + next[1];
 
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = IWEVGENIE;
-		iwe.u.data.length = next - pos;
-		*current_ev = iwe_stream_add_point(info, *current_ev,
-						   end_buf, &iwe, pos);
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVGENIE;
+			iwe.u.data.length = next - pos;
+			*current_ev = iwe_stream_add_point(info, *current_ev,
+							   end_buf, &iwe, pos);
 
-		pos = next;
-	}
+			pos = next;
+		}
 
-	if (end > pos) {
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = IWEVGENIE;
-		iwe.u.data.length = end - pos;
-		*current_ev = iwe_stream_add_point(info, *current_ev,
-						   end_buf, &iwe, pos);
+		if (end > pos) {
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVGENIE;
+			iwe.u.data.length = end - pos;
+			*current_ev = iwe_stream_add_point(info, *current_ev,
+							   end_buf, &iwe, pos);
+		}
 	}
 }
 

Index: wireless-testing/net/mac80211/util.c
===================================================================

net/mac80211/util.c +40 -0
@@ -675,6 +675,46 @@ void ieee802_11_parse_elems(u8 *start, s
 	}
 }
 
+/*
+ * ieee80211_filter_ie() tries to keep only the relevant IEs for
+ * userspace (mostly hostap code).
+ */
+int ieee80211_filter_ie(u8 *ie)
+{
+	u8 id, ie_len, *pos;
+	u8 microsoft_oui[4] = {0x00, 0x50, 0xf2};
+	u8 wpa2_oui[3] = {0x00, 0x0f, 0xac};
+
+	pos = ie;
+	id = *pos++;
+	ie_len = *pos++;
+
+	switch (id) {
+	case WLAN_EID_RSN:
+		/* WPA2 */
+		if (ie_len >= 3 &&
+		    !memcmp(pos, wpa2_oui, 3))
+			return 1;
+
+		return 0;
+
+	case WLAN_EID_VENDOR_SPECIFIC:
+		/* We're trying to catch WPA1, WMM and WPS IEs. */
+		if (ie_len >= 3 &&
+		    !memcmp(pos, microsoft_oui, 3)) {
+			if ((pos[3] == 1) || /* WPA1 */
+			    (pos[3] == 2) || /* WMM */
+			    (pos[3] == 4))   /* WPS */
+				return 1;
+		}
+
+		return 0;
+
+	default:
+		return 0;
+	}
+}
+
 void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_local *local = sdata->local;

Index: wireless-testing/net/mac80211/ieee80211_i.h
===================================================================

net/mac80211/ieee80211_i.h +1 -0
@@ -1028,6 +1028,7 @@ void ieee80211_tx_skb(struct ieee80211_s
 		      int encrypt);
 void ieee802_11_parse_elems(u8 *start, size_t len,
 			    struct ieee802_11_elems *elems);
+int ieee80211_filter_ie(u8 *ie);
 int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq);
 u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
 			      enum ieee80211_band band);
maintainer
#10 lore raw
Quoted 11 lines · Dan Williams
Quoted 10 lines · Samuel Ortiz

From: Samuel Ortiz <[email protected]>

In very dense environment, the scan result buffer can get really large, mostly due to the addition of proprietary IEs. iwlist fails, typically warning about:
"print_scanning_info: Allocation failed". wpa_supplicant fails as well, after reallocating the scan result buffer several times, up to 132 Kbytes:
[snip]
Scan results did not fit - trying larger buffer (131072 bytes) ioctl[SIOCGIWSCAN]: Argument list too long

Quoted 6 lines
Quoted 2 lines

By adding a mac80211 module parameter, we can filter the scan results and keep only the ones userspace currently worries about, i.e. WPA1, WPA2, WMM and WPS.

A somewhat more acceptable, but still unacceptable hack would be to figure out when the returned scan results buffer would be too large, and automatically filter the IEs when it would be to large.

Nope, that doesn't even work. You'd filter even before the app decided to no longer reallocate the scan buffer.

johannes

#11 lore raw
Quoted 9 lines · Johannes Berg
Quoted 6 lines · Dan Williams
Quoted 5 lines · Samuel Ortiz

"print_scanning_info: Allocation failed". wpa_supplicant fails as well, after reallocating the scan result buffer several times, up to 132 Kbytes:
[snip]
Scan results did not fit - trying larger buffer (131072 bytes) ioctl[SIOCGIWSCAN]: Argument list too long

Quoted 6 lines
Quoted 3 lines

A somewhat more acceptable, but still unacceptable hack would be to figure out when the returned scan results buffer would be too large, and automatically filter the IEs when it would be to large.

Nope, that doesn't even work. You'd filter even before the app decided to no longer reallocate the scan buffer.

There are number of issues here and I would agree that the proposed patch is not the way to go. However, I think that there could be something here that could be done to help this situation with WEXT (while agreeing that the cfg80211/nl80211 scan is going to be the proper fix for the issue).

Trying to use 131072 byte buffer is actually a bug in wpa_supplicant and even the previous attempt of 65536 is not valid. I did not realize this before, but it was pointed out to me some time ago that the length field in struct iw_point is only 16 bits, so there is actually a strict limit of 65535 bytes of data available through SIOCGIWSCAN.

65536 ends up being truncated into zero, so I would assume the largest buffer wpa_supplicant tries to use in practice is 32768 bytes. I'll fix this so that the next doubling is actually limited to 65535 (assuming it works with WEXT code in kernel). I would hope that this helps quite a bit as far as wpa_supplicant is concerned (almost doubling the maximum results buffers).

As far as a possible workaround in kernel code is concerned, length=65535 could be considered a special case. Since it is clear that userspace cannot provide a larger buffer, there is not much point in returning -E2BIG. Instead, the results could be truncated after the last BSS that fit into the buffer and that would be returned to userspace. This is likely going to be much more useful than not being able to receive any result.

Signature · 1 line
Jouni Malinen                                            PGP id EFC895FA
#12 lore raw
Quoted 6 lines · Jouni Malinen

Trying to use 131072 byte buffer is actually a bug in wpa_supplicant and even the previous attempt of 65536 is not valid. I did not realize this before, but it was pointed out to me some time ago that the length field in struct iw_point is only 16 bits, so there is actually a strict limit of 65535 bytes of data available through SIOCGIWSCAN.

Quoted 6 lines

65536 ends up being truncated into zero, so I would assume the largest buffer wpa_supplicant tries to use in practice is 32768 bytes. I'll fix this so that the next doubling is actually limited to 65535 (assuming it works with WEXT code in kernel). I would hope that this helps quite a bit as far as wpa_supplicant is concerned (almost doubling the maximum results buffers).

This moved the maximum from 88 BSSes (using IEEE 802.11g with WPA2 as an example here; smaller number for 802.11n etc. extensions) to 177 BSSes (or 178, but the last one was truncated, I think; the returned buffer was 65534 bytes long). After that, things get bad, though, since there is no way for the user space to fetch the buffer (at least with mac80211 scan reporting).

Quoted 7 lines

As far as a possible workaround in kernel code is concerned, length=65535 could be considered a special case. Since it is clear that userspace cannot provide a larger buffer, there is not much point in returning -E2BIG. Instead, the results could be truncated after the last BSS that fit into the buffer and that would be returned to userspace. This is likely going to be much more useful than not being able to receive any result.

This should have helped with the test above when the number of BSSes went past 178. Sure, all BSSes would not be reported, but should the driver do any sorting based on BSS preference (e.g., signal strength), this would likely work for most use cases.

Signature · 1 line
Jouni Malinen                                            PGP id EFC895FA
#13 lore raw
Quoted 29 lines · Jouni Malinen
Quoted 6 lines · Jouni Malinen

Trying to use 131072 byte buffer is actually a bug in wpa_supplicant and even the previous attempt of 65536 is not valid. I did not realize this before, but it was pointed out to me some time ago that the length field in struct iw_point is only 16 bits, so there is actually a strict limit of 65535 bytes of data available through SIOCGIWSCAN.

Quoted 6 lines

65536 ends up being truncated into zero, so I would assume the largest buffer wpa_supplicant tries to use in practice is 32768 bytes. I'll fix this so that the next doubling is actually limited to 65535 (assuming it works with WEXT code in kernel). I would hope that this helps quite a bit as far as wpa_supplicant is concerned (almost doubling the maximum results buffers).

This moved the maximum from 88 BSSes (using IEEE 802.11g with WPA2 as an example here; smaller number for 802.11n etc. extensions) to 177 BSSes (or 178, but the last one was truncated, I think; the returned buffer was 65534 bytes long). After that, things get bad, though, since there is no way for the user space to fetch the buffer (at least with mac80211 scan reporting).

Quoted 7 lines

As far as a possible workaround in kernel code is concerned, length=65535 could be considered a special case. Since it is clear that userspace cannot provide a larger buffer, there is not much point in returning -E2BIG. Instead, the results could be truncated after the last BSS that fit into the buffer and that would be returned to userspace. This is likely going to be much more useful than not being able to receive any result.

Quoted 4 lines

This should have helped with the test above when the number of BSSes went past 178. Sure, all BSSes would not be reported, but should the driver do any sorting based on BSS preference (e.g., signal strength), this would likely work for most use cases.

Just a thought If user space will be able to merge 2 scan results we can then split then in 2 separate reports....

Tomas

#14 lore raw
Quoted 2 lines · Tomas Winkler

Just a thought If user space will be able to merge 2 scan results we can then split then in 2 separate reports....

Theoretically speaking, yes, WEXT could be extended to do this with some kind of scan parameter that indicates which 64 kB block is requested. However, I would not suggest going there and I would probably object to a patch that tries to do this either in the kernel or in wpa_supplicant for that matter.

If you really end up hitting a case that does not work reasonably well with 64 kB fix in user space, I would suggest looking into the cfg80211/nl80211 scan stuff. The only additional thing it needs in such an environment is to get better optimized data structure (for which, there is already a proposed implementation, too).

Signature · 1 line
Jouni Malinen                                            PGP id EFC895FA
#15 lore raw
Quoted 10 lines · Jouni Malinen
Quoted 2 lines · Tomas Winkler

Just a thought If user space will be able to merge 2 scan results we can then split then in 2 separate reports....

Theoretically speaking, yes, WEXT could be extended to do this with some kind of scan parameter that indicates which 64 kB block is requested. However, I would not suggest going there and I would probably object to a patch that tries to do this either in the kernel or in wpa_supplicant for that matter.

I thin it can be done w/o extension of wext, j ust the eviction of old scan results is done
in user space.IRCC the time stamp of beacon/probe is part of each entry. And user space state machine should be able to react on nl[SIOCGIWSCAN] w/o issuing ioctl[SIOCSIWSCAN]:

Quoted 5 lines

If you really end up hitting a case that does not work reasonably well with 64 kB fix in user space, I would suggest looking into the cfg80211/nl80211 scan stuff. The only additional thing it needs in such an environment is to get better optimized data structure (for which, there is already a proposed implementation, too).

Guess we need to proceed with cfg anyway

Tomas

Quoted 3 lines

--
Jouni Malinen PGP id EFC895FA

#16 lore raw
Quoted 12 lines · Tomas Winkler
Quoted 10 lines · Jouni Malinen
Quoted 2 lines · Tomas Winkler

Just a thought If user space will be able to merge 2 scan results we can then split then in 2 separate reports....

Theoretically speaking, yes, WEXT could be extended to do this with some kind of scan parameter that indicates which 64 kB block is requested. However, I would not suggest going there and I would probably object to a patch that tries to do this either in the kernel or in wpa_supplicant for that matter.

Quoted 5 lines

I thin it can be done w/o extension of wext, j ust the eviction of old scan results is done
in user space.IRCC the time stamp of beacon/probe is part of each entry. And user space state machine should be able to react on nl[SIOCGIWSCAN] w/o issuing ioctl[SIOCSIWSCAN]:

I still don't like this. If 177 BSSes is not enough, then get the cfg80211 stuff working better for you. I can't think of how this scheme would work; which half of the results get returned when something calls SIOCGIWSCAN? Would the driver/stack internally flip to the other half of the results on each call of SIOCGIWSCAN? That doesn't work, because then two userspace processes requesting scan results will race with each other for them. We had this problem before when drivers cleared the scan list each time SIOCGIWSCAN was called.

Dan

Quoted 13 lines
Quoted 5 lines

If you really end up hitting a case that does not work reasonably well with 64 kB fix in user space, I would suggest looking into the cfg80211/nl80211 scan stuff. The only additional thing it needs in such an environment is to get better optimized data structure (for which, there is already a proposed implementation, too).

Guess we need to proceed with cfg anyway

Tomas

Quoted 3 lines

--
Jouni Malinen PGP id EFC895FA

#17 lore raw
Quoted 19 lines · Dan Williams
Quoted 12 lines · Tomas Winkler
Quoted 10 lines · Jouni Malinen
Quoted 2 lines · Tomas Winkler

Just a thought If user space will be able to merge 2 scan results we can then split then in 2 separate reports....

Theoretically speaking, yes, WEXT could be extended to do this with some kind of scan parameter that indicates which 64 kB block is requested. However, I would not suggest going there and I would probably object to a patch that tries to do this either in the kernel or in wpa_supplicant for that matter.

Quoted 5 lines

I thin it can be done w/o extension of wext, j ust the eviction of old scan results is done
in user space.IRCC the time stamp of beacon/probe is part of each entry. And user space state machine should be able to react on nl[SIOCGIWSCAN] w/o issuing ioctl[SIOCSIWSCAN]:

Quoted 8 lines

I still don't like this. If 177 BSSes is not enough, then get the cfg80211 stuff working better for you. I can't think of how this scheme would work; which half of the results get returned when something calls SIOCGIWSCAN? Would the driver/stack internally flip to the other half of the results on each call of SIOCGIWSCAN? That doesn't work, because then two userspace processes requesting scan results will race with each other for them. We had this problem before when drivers cleared the scan list each time SIOCGIWSCAN was called.

Good point. A simple token will resolve this problem but this is again changing wext which I wanted to avoid...no free lunch ( Anyhow I know it's possible but is this a common usecase that two application request scan?

Thanks
Tomas

#18 lore raw
In reply to Jouni Malinen
Quoted 7 lines · Jouni Malinen

As far as a possible workaround in kernel code is concerned, length=65535 could be considered a special case. Since it is clear that userspace cannot provide a larger buffer, there is not much point in returning -E2BIG. Instead, the results could be truncated after the last BSS that fit into the buffer and that would be returned to userspace. This is likely going to be much more useful than not being able to receive any result.

And here's an example patch on doing that for mac80211 (drivers that do not use mac80211 would need to do something similar if they want to support this mechanism). Would this change be acceptable for mac80211?

---
 net/mac80211/scan.c |   13 +++++++++++++
 1 file changed, 13 insertions(+)
net/mac80211/scan.c +13 -0
@@ -934,6 +934,19 @@ int ieee80211_scan_results(struct ieee80
 	list_for_each_entry(bss, &local->bss_list, list) {
 		if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
 			spin_unlock_bh(&local->bss_lock);
+			if (len == 65535) {
+				/*
+				 * WEXT uses 16-bit field for the length which
+				 * means that the largest buffer size that can
+				 * be used here is 65535 bytes. There is not
+				 * much help in returning -E2BIG if the user
+				 * space program cannot use a larger buffer. As
+				 * a workaround, return as many BSSes as
+				 * possible instead of making it impossible for
+				 * the application to get any results.
+				 */
+				return current_ev - buf;
+			}
 			return -E2BIG;
 		}
 		current_ev = ieee80211_scan_result(local, info, bss,
Signature · 1 line
Jouni Malinen                                            PGP id EFC895FA
maintainer
#19 lore raw
Quoted 9 lines · Jouni Malinen
Quoted 7 lines · Jouni Malinen

As far as a possible workaround in kernel code is concerned, length=65535 could be considered a special case. Since it is clear that userspace cannot provide a larger buffer, there is not much point in returning -E2BIG. Instead, the results could be truncated after the last BSS that fit into the buffer and that would be returned to userspace. This is likely going to be much more useful than not being able to receive any result.

Quoted 3 lines

And here's an example patch on doing that for mac80211 (drivers that do not use mac80211 would need to do something similar if they want to support this mechanism). Would this change be acceptable for mac80211?

Seems ok to me, since wext limits us to this anyway... But can we rely on userspace to (a) use the exactly largest buffer size and (b) be able to interpret that?

johannes

Quoted 27 lines
---
 net/mac80211/scan.c |   13 +++++++++++++
 1 file changed, 13 insertions(+)
net/mac80211/scan.c +13 -0
@@ -934,6 +934,19 @@ int ieee80211_scan_results(struct ieee80
 	list_for_each_entry(bss, &local->bss_list, list) {
 		if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
 			spin_unlock_bh(&local->bss_lock);
+			if (len == 65535) {
+				/*
+				 * WEXT uses 16-bit field for the length which
+				 * means that the largest buffer size that can
+				 * be used here is 65535 bytes. There is not
+				 * much help in returning -E2BIG if the user
+				 * space program cannot use a larger buffer. As
+				 * a workaround, return as many BSSes as
+				 * possible instead of making it impossible for
+				 * the application to get any results.
+				 */
+				return current_ev - buf;
+			}
 			return -E2BIG;
 		}
 		current_ev = ieee80211_scan_result(local, info, bss,
#20 lore raw
Quoted 3 lines · Johannes Berg

Seems ok to me, since wext limits us to this anyway... But can we rely on userspace to (a) use the exactly largest buffer size and (b) be able to interpret that?

(a) Currently not, but once people realize that the length field has a maximum value of 65535, using it as the largest attempt sounds like the most logical choice. In other words, yes, this will require a small change in programs that care (wpa_supplicant, which I already changed; iwlist; etc.), but the change is minimal and not doing this does not break anything new.

(b) Yes, user space apps better be prepared to read the results even if the last entry is truncated (can happen with current kernel). There is no clear way for the app to know that there could be more scan results (well, it could guess that this is the case if the returned buffer is very close to 64 kB), but it is not like scanning is that reliable operation anyway, so applications better be prepared to not always find every BSS in the results.

Signature · 1 line
Jouni Malinen                                            PGP id EFC895FA
maintainer
#21 lore raw
Quoted 6 lines · Jouni Malinen

(a) Currently not, but once people realize that the length field has a maximum value of 65535, using it as the largest attempt sounds like the most logical choice. In other words, yes, this will require a small change in programs that care (wpa_supplicant, which I already changed; iwlist; etc.), but the change is minimal and not doing this does not break anything new.

True.

Quoted 7 lines

(b) Yes, user space apps better be prepared to read the results even if the last entry is truncated (can happen with current kernel). There is no clear way for the app to know that there could be more scan results (well, it could guess that this is the case if the returned buffer is very close to 64 kB), but it is not like scanning is that reliable operation anyway, so applications better be prepared to not always find every BSS in the results.

Yeah, the truncation is a little worrying. I doubt any program but wpa_supplicant is prepared to handle that. Should we completely remove the entry, and add some new/custom piece to stream that indicates that we had to truncate here?

johannes

#22 lore raw
Quoted 4 lines · Johannes Berg

Yeah, the truncation is a little worrying. I doubt any program but wpa_supplicant is prepared to handle that. Should we completely remove the entry, and add some new/custom piece to stream that indicates that we had to truncate here?

Well, the truncation is partly an artifact of the way iwe_stream_* helpers work and I would expect all drivers to be doing this already (should they support large enough number of BSSes to hit the limit). If I have understood correctly, truncation happens between events, i.e., no event (struct iw_event) itself is truncated; some events are just missing from a BSS. As such, I would expect more or less all application to handle that one way or another. They may assume the network does not support WPA etc. based on some iw_events missing, but that should be about it.

It would be somewhat cleaner to truncate between BSSes instead of between iw_events, but it would be some more code (remember the length before starting to add new BSS and use it if truncations was detected). I don't think I would bother with custom iw_event stating that truncation happened since I do not see much use for it in wpa_supplicant. It could be of some use for someone running iwlist scan manually.

Signature · 1 line
Jouni Malinen                                            PGP id EFC895FA
maintainer
#23 lore raw
Quoted 3 lines · Jouni Malinen

It would be somewhat cleaner to truncate between BSSes instead of between iw_events, but it would be some more code (remember the length before starting to add new BSS and use it if truncations was detected).

Doesn't seem that hard? Want to post the patch for cfg80211?

Quoted 4 lines

I don't think I would bother with custom iw_event stating that truncation happened since I do not see much use for it in wpa_supplicant. It could be of some use for someone running iwlist scan manually.

Yeah, true, no use since you can't get at the other results anyway... Just use nl80211 :)

johannes