Fix test-sha256 build
[wpasupplicant] / wpa_supplicant / wps_supplicant.c
index a538338..9b73601 100644 (file)
 #include "eloop.h"
 #include "uuid.h"
 #include "wpa_ctrl.h"
+#include "ctrl_iface_dbus.h"
 #include "eap_common/eap_wsc_common.h"
-#include "wps/wps.h"
-#include "wps/wps_defs.h"
+#include "blacklist.h"
 #include "wps_supplicant.h"
 
+#define WPS_PIN_SCAN_IGNORE_SEL_REG 3
 
 static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
 static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
@@ -35,6 +36,27 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
 
 int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
 {
+       if (!wpa_s->wps_success &&
+           wpa_s->current_ssid &&
+           eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
+               const u8 *bssid = wpa_s->bssid;
+               if (is_zero_ether_addr(bssid))
+                       bssid = wpa_s->pending_bssid;
+
+               wpa_printf(MSG_DEBUG, "WPS: PIN registration with " MACSTR
+                          " did not succeed - continue trying to find "
+                          "suitable AP", MAC2STR(bssid));
+               wpa_blacklist_add(wpa_s, bssid);
+
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
+               wpa_s->reassociate = 1;
+               wpa_supplicant_req_scan(wpa_s,
+                                       wpa_s->blacklist_cleared ? 5 : 0, 0);
+               wpa_s->blacklist_cleared = 0;
+               return 1;
+       }
+
        eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
 
        if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid &&
@@ -48,6 +70,15 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
                return 1;
        }
 
+       if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid) {
+               wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting "
+                          "for external credential processing");
+               wpas_clear_wps(wpa_s);
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
+               return 1;
+       }
+
        return 0;
 }
 
@@ -58,7 +89,36 @@ static int wpa_supplicant_wps_cred(void *ctx,
        struct wpa_supplicant *wpa_s = ctx;
        struct wpa_ssid *ssid = wpa_s->current_ssid;
 
-       wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED);
+       if ((wpa_s->conf->wps_cred_processing == 1 ||
+            wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) {
+               size_t blen = cred->cred_attr_len * 2 + 1;
+               char *buf = os_malloc(blen);
+               if (buf) {
+                       wpa_snprintf_hex(buf, blen,
+                                        cred->cred_attr, cred->cred_attr_len);
+                       wpa_msg(wpa_s, MSG_INFO, "%s%s",
+                               WPS_EVENT_CRED_RECEIVED, buf);
+                       os_free(buf);
+               }
+               wpa_supplicant_dbus_notify_wps_cred(wpa_s, cred);
+       } else
+               wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED);
+
+       wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
+                       cred->cred_attr, cred->cred_attr_len);
+
+       if (wpa_s->conf->wps_cred_processing == 1)
+               return 0;
+
+       if (cred->auth_type != WPS_AUTH_OPEN &&
+           cred->auth_type != WPS_AUTH_SHARED &&
+           cred->auth_type != WPS_AUTH_WPAPSK &&
+           cred->auth_type != WPS_AUTH_WPA2PSK) {
+               wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
+                          "unsupported authentication type %d",
+                          cred->auth_type);
+               return 0;
+       }
 
        if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
                wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
@@ -89,11 +149,8 @@ static int wpa_supplicant_wps_cred(void *ctx,
 
        switch (cred->encr_type) {
        case WPS_ENCR_NONE:
-               ssid->pairwise_cipher = ssid->group_cipher = WPA_CIPHER_NONE;
                break;
        case WPS_ENCR_WEP:
-               ssid->pairwise_cipher = ssid->group_cipher =
-                       WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104;
                if (cred->key_len > 0 && cred->key_len <= MAX_WEP_KEY_LEN &&
                    cred->key_idx < NUM_WEP_KEYS) {
                        os_memcpy(ssid->wep_key[cred->key_idx], cred->key,
@@ -104,11 +161,9 @@ static int wpa_supplicant_wps_cred(void *ctx,
                break;
        case WPS_ENCR_TKIP:
                ssid->pairwise_cipher = WPA_CIPHER_TKIP;
-               ssid->group_cipher = WPA_CIPHER_TKIP;
                break;
        case WPS_ENCR_AES:
                ssid->pairwise_cipher = WPA_CIPHER_CCMP;
-               ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
                break;
        }
 
@@ -202,6 +257,7 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
 static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
 {
        wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
+       wpa_s->wps_success = 1;
 }
 
 
@@ -219,11 +275,13 @@ static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
        case WPS_EV_SUCCESS:
                wpa_supplicant_wps_event_success(wpa_s);
                break;
+       case WPS_EV_PWD_AUTH_FAIL:
+               break;
        }
 }
 
 
-u8 wpas_wps_get_req_type(struct wpa_ssid *ssid)
+enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid)
 {
        if (eap_is_wps_pbc_enrollee(&ssid->eap) ||
            eap_is_wps_pin_enrollee(&ssid->eap))
@@ -259,7 +317,8 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
 static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_supplicant *wpa_s = eloop_ctx;
-       wpa_printf(MSG_DEBUG, "WPS: Requested operation timed out");
+       wpa_printf(MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed "
+                  "out");
        wpas_clear_wps(wpa_s);
 }
 
@@ -331,6 +390,9 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
        }
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
+       wpa_s->scan_runs = 0;
+       wpa_s->wps_success = 0;
+       wpa_s->blacklist_cleared = 0;
        wpa_supplicant_req_scan(wpa_s, 0, 0);
 }
 
@@ -396,9 +458,42 @@ int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
 }
 
 
+static int wpas_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
+                              size_t psk_len)
+{
+       wpa_printf(MSG_DEBUG, "WPS: Received new WPA/WPA2-PSK from WPS for "
+                  "STA " MACSTR, MAC2STR(mac_addr));
+       wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
+
+       /* TODO */
+
+       return 0;
+}
+
+
+static void wpas_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
+                                  const struct wps_device_data *dev)
+{
+       char uuid[40], txt[400];
+       int len;
+       if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
+               return;
+       wpa_printf(MSG_DEBUG, "WPS: PIN needed for UUID-E %s", uuid);
+       len = os_snprintf(txt, sizeof(txt), "WPS-EVENT-PIN-NEEDED %s " MACSTR
+                         " [%s|%s|%s|%s|%s|%d-%08X-%d]",
+                         uuid, MAC2STR(dev->mac_addr), dev->device_name,
+                         dev->manufacturer, dev->model_name,
+                         dev->model_number, dev->serial_number,
+                         dev->categ, dev->oui, dev->sub_categ);
+       if (len > 0 && len < (int) sizeof(txt))
+               wpa_printf(MSG_INFO, "%s", txt);
+}
+
+
 int wpas_wps_init(struct wpa_supplicant *wpa_s)
 {
        struct wps_context *wps;
+       struct wps_registrar_config rcfg;
 
        wps = os_zalloc(sizeof(*wps));
        if (wps == NULL)
@@ -450,6 +545,21 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
        } else
                os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
 
+       wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
+       wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
+
+       os_memset(&rcfg, 0, sizeof(rcfg));
+       rcfg.new_psk_cb = wpas_wps_new_psk_cb;
+       rcfg.pin_needed_cb = wpas_wps_pin_needed_cb;
+       rcfg.cb_ctx = wpa_s;
+
+       wps->registrar = wps_registrar_init(wps, &rcfg);
+       if (wps->registrar == NULL) {
+               wpa_printf(MSG_DEBUG, "Failed to initialize WPS Registrar");
+               os_free(wps);
+               return -1;
+       }
+
        wpa_s->wps = wps;
 
        return 0;
@@ -463,13 +573,15 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
        if (wpa_s->wps == NULL)
                return;
 
+       wps_registrar_deinit(wpa_s->wps->registrar);
        os_free(wpa_s->wps->network_key);
        os_free(wpa_s->wps);
        wpa_s->wps = NULL;
 }
 
 
-int wpas_wps_ssid_bss_match(struct wpa_ssid *ssid, struct wpa_scan_res *bss)
+int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
+                           struct wpa_ssid *ssid, struct wpa_scan_res *bss)
 {
        struct wpabuf *wps_ie;
 
@@ -503,14 +615,24 @@ int wpas_wps_ssid_bss_match(struct wpa_ssid *ssid, struct wpa_scan_res *bss)
                        return 0;
                }
 
+               /*
+                * Start with WPS APs that advertise active PIN Registrar and
+                * allow any WPS AP after third scan since some APs do not set
+                * Selected Registrar attribute properly when using external
+                * Registrar.
+                */
                if (!wps_is_selected_pin_registrar(wps_ie)) {
-                       wpa_printf(MSG_DEBUG, "   skip - WPS AP "
-                                  "without active PIN Registrar");
-                       wpabuf_free(wps_ie);
-                       return 0;
+                       if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) {
+                               wpa_printf(MSG_DEBUG, "   skip - WPS AP "
+                                          "without active PIN Registrar");
+                               wpabuf_free(wps_ie);
+                               return 0;
+                       }
+                       wpa_printf(MSG_DEBUG, "   selected based on WPS IE");
+               } else {
+                       wpa_printf(MSG_DEBUG, "   selected based on WPS IE "
+                                  "(Active PIN)");
                }
-               wpa_printf(MSG_DEBUG, "   selected based on WPS IE "
-                          "(Active PIN)");
                wpabuf_free(wps_ie);
                return 1;
        }
@@ -525,7 +647,8 @@ int wpas_wps_ssid_bss_match(struct wpa_ssid *ssid, struct wpa_scan_res *bss)
 }
 
 
-int wpas_wps_ssid_wildcard_ok(struct wpa_ssid *ssid,
+int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
+                             struct wpa_ssid *ssid,
                              struct wpa_scan_res *bss)
 {
        struct wpabuf *wps_ie = NULL;
@@ -539,7 +662,9 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_ssid *ssid,
                }
        } else if (eap_is_wps_pin_enrollee(&ssid->eap)) {
                wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
-               if (wps_ie && wps_is_selected_pin_registrar(wps_ie)) {
+               if (wps_ie &&
+                   (wps_is_selected_pin_registrar(wps_ie) ||
+                    wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) {
                        /* allow wildcard SSID for WPS PIN */
                        ret = 1;
                }