[PATCH] `iwlist scan` fails with many networks available
From: James Nylen
Date: Sat Aug 10 2019 - 22:08:21 EST
In 5.x it's still possible for `ieee80211_scan_results` (`iwlist
scan`) to fail when too many wireless networks are available. This
code path is used by `wicd`.
Previously: https://lkml.org/lkml/2017/4/2/192
I've been applying this updated patch to my own kernels since 2017 with
no issues. I am sure it is not the ideal way to solve this problem, but
I'm making my fix available in case it helps others.
Please advise on next steps or if this is a dead end.
commit 8e80dcb0df71ac8f5d3640bcdb1bba9c7693d63a
Author: James Nylen <jnylen@xxxxxxxxx>
Date: Wed Apr 26 14:38:58 2017 +0200
Hack: Make `ieee80211_scan_results` (`iwlist scan`) return less E2BIG
See: https://lkml.org/lkml/2017/4/2/192
(and branch `jcn/hack/wireless-scan-no-e2big`)
This should really be done with a bigger limit inside the `iwlist` code
instead, if possible (or even better: modify `wicd` to use `iw scan`
instead).
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 21be56b3128e..08fa9cb68f59 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -1699,6 +1699,7 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *rdev,
struct iw_request_info *info,
char *buf, size_t len)
{
+ char *maybe_current_ev;
char *current_ev = buf;
char *end_buf = buf + len;
struct cfg80211_internal_bss *bss;
@@ -1709,14 +1710,29 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *rdev,
list_for_each_entry(bss, &rdev->bss_list, list) {
if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
- err = -E2BIG;
+ // Buffer too small to hold another BSS. Only report
+ // an error if we have not yet reached the maximum
+ // buffer size that `iwlist` can handle.
+ if (len < 0xFFFF) {
+ err = -E2BIG;
+ }
break;
}
- current_ev = ieee80211_bss(&rdev->wiphy, info, bss,
- current_ev, end_buf);
- if (IS_ERR(current_ev)) {
- err = PTR_ERR(current_ev);
+ maybe_current_ev = ieee80211_bss(&rdev->wiphy, info, bss,
+ current_ev, end_buf);
+ if (IS_ERR(maybe_current_ev)) {
+ err = PTR_ERR(maybe_current_ev);
+ if (err == -E2BIG) {
+ // Last BSS failed to copy into buffer. As
+ // above, only report an error if `iwlist` will
+ // retry again with a larger buffer.
+ if (len >= 0xFFFF) {
+ err = 0;
+ }
+ }
break;
+ } else {
+ current_ev = maybe_current_ev;
}
}
spin_unlock_bh(&rdev->bss_lock);