Messages in this thread Patch in this message | | | From | James Nylen <> | Date | Sun, 2 Apr 2017 14:39:42 -0700 | Subject | `iwlist scan` fails with many networks available |
| |
I've spent the past few days in a large hotel and noticed that `iwlist scan` fails with the error message "Argument list too long".
This seems to be because there are a great many wireless networks in my vicinity. See: https://bugzilla.kernel.org/show_bug.cgi?id=16384
Using `iw` as recommended in that ticket works, but it's not a great option for me because `wicd` doesn't support it.
If I'm understanding the relevant code correctly, the attached patch works around the issue by skipping networks that would not fit in the scan-results buffer and returning partial results instead of just erroring out.
This is the first time I've modified the kernel code directly. I have a couple of questions:
- This seems to be working like I intended, but the condition was a bit hard to reproduce consistently. Am I inadvertently breaking things? - Is there a better way to accomplish this? Reading the `iwlist` code I'm not entirely sure why this is occurring, because it looks like it should be allocating a dynamic buffer length. diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 21be56b..fc74091 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,20 @@ 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 big to hold another BSS; ignore 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; ignore + err = 0; + } break; + } else { + current_ev = maybe_current_ev; } } spin_unlock_bh(&rdev->bss_lock); | |