diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 4051fbc28..e424c6f06 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -5213,6 +5213,92 @@ static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx) } +static int set_scan_freqs(struct wpa_supplicant *wpa_s, char *val) +{ + struct wpa_freq_range_list ranges; + int *freqs = NULL; + struct hostapd_hw_modes *mode; + u16 i; + + if (wpa_s->hw.modes == NULL) + return -1; + + os_memset(&ranges, 0, sizeof(ranges)); + if (freq_range_list_parse(&ranges, val) < 0) + return -1; + + for (i = 0; i < wpa_s->hw.num_modes; i++) { + int j; + + mode = &wpa_s->hw.modes[i]; + for (j = 0; j < mode->num_channels; j++) { + unsigned int freq; + + if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED) + continue; + + freq = mode->channels[j].freq; + if (!freq_range_list_includes(&ranges, freq)) + continue; + + int_array_add_unique(&freqs, freq); + } + } + + os_free(ranges.range); + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = freqs; + + return 0; +} + + +static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params, + char *reply, int reply_size, int *reply_len) +{ + char *pos; + + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { + *reply_len = -1; + return; + } + + if (params) { + if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0) + wpa_s->scan_res_handler = scan_only_handler; + + pos = os_strstr(params, "freq="); + if (pos && set_scan_freqs(wpa_s, pos + 5) < 0) { + *reply_len = -1; + return; + } + } else { + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = NULL; + if (wpa_s->scan_res_handler == scan_only_handler) + wpa_s->scan_res_handler = NULL; + } + + if (!wpa_s->sched_scanning && !wpa_s->scanning && + ((wpa_s->wpa_state <= WPA_SCANNING) || + (wpa_s->wpa_state == WPA_COMPLETED))) { + wpa_s->normal_scans = 0; + wpa_s->scan_req = MANUAL_SCAN_REQ; + wpa_s->after_wps = 0; + wpa_s->known_wps_freq = 0; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } else if (wpa_s->sched_scanning) { + wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed"); + wpa_supplicant_cancel_sched_scan(wpa_s); + wpa_s->scan_req = MANUAL_SCAN_REQ; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } else { + wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request"); + *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n"); + } +} + + char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, char *buf, size_t *resp_len) { @@ -5591,36 +5677,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, wpa_supplicant_cancel_scan(wpa_s); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); - } else if (os_strcmp(buf, "SCAN") == 0 || - os_strncmp(buf, "SCAN ", 5) == 0) { - if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) - reply_len = -1; - else { - if (os_strlen(buf) > 4 && - os_strncasecmp(buf + 5, "TYPE=ONLY", 9) == 0) - wpa_s->scan_res_handler = scan_only_handler; - if (!wpa_s->sched_scanning && !wpa_s->scanning && - ((wpa_s->wpa_state <= WPA_SCANNING) || - (wpa_s->wpa_state == WPA_COMPLETED))) { - wpa_s->normal_scans = 0; - wpa_s->scan_req = MANUAL_SCAN_REQ; - wpa_s->after_wps = 0; - wpa_s->known_wps_freq = 0; - wpa_supplicant_req_scan(wpa_s, 0, 0); - } else if (wpa_s->sched_scanning) { - wpa_printf(MSG_DEBUG, "Stop ongoing " - "sched_scan to allow requested " - "full scan to proceed"); - wpa_supplicant_cancel_sched_scan(wpa_s); - wpa_s->scan_req = MANUAL_SCAN_REQ; - wpa_supplicant_req_scan(wpa_s, 0, 0); - } else { - wpa_printf(MSG_DEBUG, "Ongoing scan action - " - "reject new request"); - reply_len = os_snprintf(reply, reply_size, - "FAIL-BUSY\n"); - } - } + } else if (os_strcmp(buf, "SCAN") == 0) { + wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len); + } else if (os_strncmp(buf, "SCAN ", 5) == 0) { + wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len); } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) { reply_len = wpa_supplicant_ctrl_iface_scan_results( wpa_s, reply, reply_size); diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 70ce76778..c22ffbf2e 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -711,6 +711,13 @@ ssid_list_set: wpa_supplicant_optimize_freqs(wpa_s, ¶ms); extra_ie = wpa_supplicant_extra_ies(wpa_s); + if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL && + wpa_s->manual_scan_freqs) { + wpa_dbg(wpa_s, MSG_DEBUG, "Limit manual scan to specified channels"); + params.freqs = wpa_s->manual_scan_freqs; + wpa_s->manual_scan_freqs = NULL; + } + if (params.freqs == NULL && wpa_s->next_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously " "generated frequency list"); @@ -799,6 +806,13 @@ scan: ret = wpa_supplicant_trigger_scan(wpa_s, scan_params); + if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs && + !wpa_s->manual_scan_freqs) { + /* Restore manual_scan_freqs for the next attempt */ + wpa_s->manual_scan_freqs = params.freqs; + params.freqs = NULL; + } + wpabuf_free(extra_ie); os_free(params.freqs); os_free(params.filter_ssids); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 897974b6f..095ab97c1 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -459,6 +459,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) os_free(wpa_s->next_scan_freqs); wpa_s->next_scan_freqs = NULL; + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = NULL; + gas_query_deinit(wpa_s->gas); wpa_s->gas = NULL; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 5cb767406..68f508a98 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -482,6 +482,7 @@ struct wpa_supplicant { struct os_reltime scan_trigger_time; int scan_runs; /* number of scan runs since WPS was started */ int *next_scan_freqs; + int *manual_scan_freqs; int scan_interval; /* time in sec between scans to find suitable AP */ int normal_scans; /* normal scans run before sched_scan */ int scan_for_connection; /* whether the scan request was triggered for