diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index c6eca92ca..998b3948b 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -398,7 +398,21 @@ static int send_and_recv(struct nl80211_global *global, while (err > 0) { int res = nl_recvmsgs(nl_handle, cb); - if (res < 0) { + + if (res == -NLE_DUMP_INTR) { + /* Most likely one of the nl80211 dump routines hit a + * case where internal results changed while the dump + * was being sent. The most common known case for this + * is scan results fetching while associated were every + * received Beacon frame from the AP may end up + * incrementing bss_generation. This + * NL80211_CMD_GET_SCAN case tries again in the caller; + * other cases (of which there are no known common ones) + * will stop and return an error. */ + wpa_printf(MSG_DEBUG, "nl80211: %s; convert to -EAGAIN", + nl_geterror(res)); + err = -EAGAIN; + } else if (res < 0) { wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d (%s)", __func__, res, nl_geterror(res)); @@ -1336,12 +1350,25 @@ int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid) struct nl_msg *msg; int ret; struct nl80211_get_assoc_freq_arg arg; + int count = 0; +try_again: msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN); os_memset(&arg, 0, sizeof(arg)); arg.drv = drv; ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler, &arg); + if (ret == -EAGAIN) { + count++; + if (count >= 10) { + wpa_printf(MSG_INFO, + "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid"); + } else { + wpa_printf(MSG_DEBUG, + "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid - try again"); + goto try_again; + } + } if (ret == 0) { os_memcpy(ssid, arg.assoc_ssid, arg.assoc_ssid_len); return arg.assoc_ssid_len; @@ -1357,12 +1384,25 @@ unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv) struct nl_msg *msg; int ret; struct nl80211_get_assoc_freq_arg arg; + int count = 0; +try_again: msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN); os_memset(&arg, 0, sizeof(arg)); arg.drv = drv; ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler, &arg); + if (ret == -EAGAIN) { + count++; + if (count >= 10) { + wpa_printf(MSG_INFO, + "nl80211: Failed to receive consistent scan result dump for get_assoc_freq"); + } else { + wpa_printf(MSG_DEBUG, + "nl80211: Failed to receive consistent scan result dump for get_assoc_freq - try again"); + goto try_again; + } + } if (ret == 0) { unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ? arg.ibss_freq : arg.assoc_freq; diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c index 9afa5b304..413d6f757 100644 --- a/src/drivers/driver_nl80211_scan.c +++ b/src/drivers/driver_nl80211_scan.c @@ -928,7 +928,9 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) struct wpa_scan_results *res; int ret; struct nl80211_bss_info_arg arg; + int count = 0; +try_again: res = os_zalloc(sizeof(*res)); if (res == NULL) return NULL; @@ -941,6 +943,18 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) arg.drv = drv; arg.res = res; ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); + if (ret == -EAGAIN) { + count++; + if (count >= 10) { + wpa_printf(MSG_INFO, + "nl80211: Failed to receive consistent scan result dump"); + } else { + wpa_printf(MSG_DEBUG, + "nl80211: Failed to receive consistent scan result dump - try again"); + wpa_scan_results_free(res); + goto try_again; + } + } if (ret == 0) { struct nl80211_noise_info info;