WPS: Use different scan result sorting rules when doing WPS provisioning

The AP configuration may change after provisioning, so it is better
not to use the current security policy to prioritize results. Instead,
use WPS Selected Registrar attribute as the main sorting key and use
signal strength next without considering security policy or rate sets.
The non-WPS provisioning case remains as-is, i.e., this change applies
only when trying to find an AP for WPS provisioning.
This commit is contained in:
Jouni Malinen 2010-06-11 13:50:13 -07:00 committed by Jouni Malinen
parent f62c2315f7
commit 41e650ae5c
5 changed files with 104 additions and 1 deletions

View File

@ -236,6 +236,36 @@ int wps_is_selected_pin_registrar(const struct wpabuf *msg)
}
/**
* wps_ap_priority_compar - Prioritize WPS IE from two APs
* @wps_a: WPS IE contents from Beacon or Probe Response frame
* @wps_b: WPS IE contents from Beacon or Probe Response frame
* Returns: 1 if wps_b is considered more likely selection for WPS
* provisioning, -1 if wps_a is considered more like, or 0 if no preference
*/
int wps_ap_priority_compar(const struct wpabuf *wps_a,
const struct wpabuf *wps_b)
{
struct wps_parse_attr attr_a, attr_b;
int sel_a, sel_b;
if (wps_a == NULL || wps_parse_msg(wps_a, &attr_a) < 0)
return 1;
if (wps_b == NULL || wps_parse_msg(wps_b, &attr_b) < 0)
return -1;
sel_a = attr_a.selected_registrar && *attr_a.selected_registrar != 0;
sel_b = attr_b.selected_registrar && *attr_b.selected_registrar != 0;
if (sel_a && !sel_b)
return -1;
if (!sel_a && sel_b)
return 1;
return 0;
}
/**
* wps_get_uuid_e - Get UUID-E from WPS IE
* @msg: WPS IE contents from Beacon or Probe Response frame

View File

@ -195,6 +195,8 @@ struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code);
int wps_is_selected_pbc_registrar(const struct wpabuf *msg);
int wps_is_selected_pin_registrar(const struct wpabuf *msg);
int wps_ap_priority_compar(const struct wpabuf *wps_a,
const struct wpabuf *wps_b);
const u8 * wps_get_uuid_e(const struct wpabuf *msg);
struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type);

View File

@ -641,6 +641,54 @@ static int wpa_scan_result_compar(const void *a, const void *b)
}
#ifdef CONFIG_WPS
/* Compare function for sorting scan results when searching a WPS AP for
* provisioning. Return >0 if @b is considered better. */
static int wpa_scan_result_wps_compar(const void *a, const void *b)
{
struct wpa_scan_res **_wa = (void *) a;
struct wpa_scan_res **_wb = (void *) b;
struct wpa_scan_res *wa = *_wa;
struct wpa_scan_res *wb = *_wb;
int uses_wps_a, uses_wps_b;
struct wpabuf *wps_a, *wps_b;
int res;
/* Optimization - check WPS IE existence before allocated memory and
* doing full reassembly. */
uses_wps_a = wpa_scan_get_vendor_ie(wa, WPS_IE_VENDOR_TYPE) != NULL;
uses_wps_b = wpa_scan_get_vendor_ie(wb, WPS_IE_VENDOR_TYPE) != NULL;
if (uses_wps_a && !uses_wps_b)
return -1;
if (!uses_wps_a && uses_wps_b)
return 1;
if (uses_wps_a && uses_wps_b) {
wps_a = wpa_scan_get_vendor_ie_multi(wa, WPS_IE_VENDOR_TYPE);
wps_b = wpa_scan_get_vendor_ie_multi(wb, WPS_IE_VENDOR_TYPE);
res = wps_ap_priority_compar(wps_a, wps_b);
wpabuf_free(wps_a);
wpabuf_free(wps_b);
if (res)
return res;
}
/*
* Do not use current AP security policy as a sorting criteria during
* WPS provisioning step since the AP may get reconfigured at the
* completion of provisioning.
*/
/* all things being equal, use signal level; if signal levels are
* identical, use quality values since some drivers may only report
* that value and leave the signal level zero */
if (wb->level == wa->level)
return wb->qual - wa->qual;
return wb->level - wa->level;
}
#endif /* CONFIG_WPS */
/**
* wpa_supplicant_get_scan_results - Get scan results
* @wpa_s: Pointer to wpa_supplicant data
@ -658,6 +706,7 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
{
struct wpa_scan_results *scan_res;
size_t i;
int (*compar)(const void *, const void *) = wpa_scan_result_compar;
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
scan_res = ieee80211_sta_get_scan_results(wpa_s);
@ -668,8 +717,16 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
return NULL;
}
#ifdef CONFIG_WPS
if (wpas_wps_in_progress(wpa_s)) {
wpa_printf(MSG_DEBUG, "WPS: Order scan results with WPS "
"provisioning rules");
compar = wpa_scan_result_wps_compar;
}
#endif /* CONFIG_WPS */
qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *),
wpa_scan_result_compar);
compar);
wpa_bss_update_start(wpa_s);
for (i = 0; i < scan_res->num; i++)

View File

@ -1264,3 +1264,16 @@ int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_WPS_ER */
return 0;
}
int wpas_wps_in_progress(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid;
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
if (!ssid->disabled && ssid->key_mgmt == WPA_KEY_MGMT_WPS)
return 1;
}
return 0;
}

View File

@ -62,6 +62,7 @@ int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
const char *pin, struct wps_new_ap_settings *settings);
int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s);
int wpas_wps_in_progress(struct wpa_supplicant *wpa_s);
#else /* CONFIG_WPS */