]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WPS: Use different scan result sorting rules when doing WPS provisioning
authorJouni Malinen <jouni.malinen@atheros.com>
Fri, 11 Jun 2010 20:50:13 +0000 (13:50 -0700)
committerJouni Malinen <j@w1.fi>
Fri, 11 Jun 2010 20:50:13 +0000 (13:50 -0700)
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.

src/wps/wps.c
src/wps/wps.h
wpa_supplicant/scan.c
wpa_supplicant/wps_supplicant.c
wpa_supplicant/wps_supplicant.h

index 619af158df5971df29eb070af71faa11a0be3577..f7ff2496e63628d25bb8981e2c6b98548041a2ea 100644 (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
index 41082aad2d4e7ef79592073efded6086d84f5a67..8536499d7b4c9bcc0cb745ca79cd617aeabec60f 100644 (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);
index fd01bb8faed739d311460eb05b73572e86494ab2..90d40c80226bfd4df0179b9dff61da4e8484c762 100644 (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++)
index 2b90e5746cd3f3898e373b528d1b8b2fc8d50333..db615f635ef23c7be6f5d65cc59ed2f1c06d6d73 100644 (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;
+}
index 701bcb577086d98cbe809678e3cd3b304f9a01a8..5417c501eeee84d531b75bf6a7dd0af76441c3ef 100644 (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 */