X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=wpa_supplicant%2Fwps_supplicant.c;h=af8c4c4248eb2e7aeca92b286c933ed617057001;hb=HEAD;hp=2833e21b5ffe0acb619217ef7fcf3ee9f910705b;hpb=3acb50056cf3e9e3f4a9776d5f2cbdf75fe0ae8c;p=libeap.git diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 2833e21..af8c4c4 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -1,6 +1,6 @@ /* * wpa_supplicant / WPS integration - * Copyright (c) 2008, Jouni Malinen + * Copyright (c) 2008-2010, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -15,24 +15,32 @@ #include "includes.h" #include "common.h" +#include "eloop.h" +#include "uuid.h" +#include "crypto/dh_group5.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_common.h" -#include "config.h" +#include "common/wpa_ctrl.h" +#include "eap_common/eap_wsc_common.h" #include "eap_peer/eap.h" +#include "rsn_supp/wpa.h" +#include "config.h" #include "wpa_supplicant_i.h" #include "driver_i.h" -#include "eloop.h" -#include "uuid.h" -#include "common/wpa_ctrl.h" #include "notify.h" -#include "eap_common/eap_wsc_common.h" #include "blacklist.h" -#include "rsn_supp/wpa.h" +#include "bss.h" +#include "scan.h" +#include "ap.h" +#include "p2p/p2p.h" +#include "p2p_supplicant.h" #include "wps_supplicant.h" -#include "dh_group5.h" + +#ifndef WPS_PIN_SCAN_IGNORE_SEL_REG #define WPS_PIN_SCAN_IGNORE_SEL_REG 3 +#endif /* WPS_PIN_SCAN_IGNORE_SEL_REG */ static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx); static void wpas_clear_wps(struct wpa_supplicant *wpa_s); @@ -69,6 +77,8 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) "try to associate with the received credential"); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + wpa_s->after_wps = 5; + wpa_s->wps_freq = wpa_s->assoc_freq; wpa_s->reassociate = 1; wpa_supplicant_req_scan(wpa_s, 0, 0); return 1; @@ -92,8 +102,7 @@ static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s, const struct wps_credential *cred) { struct wpa_driver_capa capa; - size_t i; - struct wpa_scan_res *bss; + struct wpa_bss *bss; const u8 *ie; struct wpa_ie_data adv; int wpa2 = 0, ccmp = 0; @@ -109,38 +118,22 @@ static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s, if (wpa_drv_get_capa(wpa_s, &capa)) return; /* Unknown what driver supports */ - if (wpa_supplicant_get_scan_results(wpa_s) || wpa_s->scan_res == NULL) - return; /* Could not get scan results for checking advertised - * parameters */ - - for (i = 0; i < wpa_s->scan_res->num; i++) { - bss = wpa_s->scan_res->res[i]; - if (os_memcmp(bss->bssid, cred->mac_addr, ETH_ALEN) != 0) - continue; - ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); - if (ie == NULL) - continue; - if (ie[1] != ssid->ssid_len || ssid->ssid == NULL || - os_memcmp(ie + 2, ssid->ssid, ssid->ssid_len) != 0) - continue; - - wpa_printf(MSG_DEBUG, "WPS: AP found from scan results"); - break; - } - - if (i == wpa_s->scan_res->num) { - wpa_printf(MSG_DEBUG, "WPS: The AP was not found from scan " - "results - use credential as-is"); + bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len); + if (bss == NULL) { + wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS " + "table - use credential as-is"); return; } - ie = wpa_scan_get_ie(bss, WLAN_EID_RSN); + wpa_printf(MSG_DEBUG, "WPS: AP found from BSS table"); + + ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0) { wpa2 = 1; if (adv.pairwise_cipher & WPA_CIPHER_CCMP) ccmp = 1; } else { - ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); + ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0 && adv.pairwise_cipher & WPA_CIPHER_CCMP) ccmp = 1; @@ -250,6 +243,8 @@ static int wpa_supplicant_wps_cred(void *ctx, ssid->eap.phase1 = NULL; os_free(ssid->eap.eap_methods); ssid->eap.eap_methods = NULL; + if (!ssid->p2p_group) + ssid->temporary = 0; } else { wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the " "received credential"); @@ -396,7 +391,12 @@ static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s, static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail) { - wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL "msg=%d", fail->msg); + wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL "msg=%d config_error=%d", + fail->msg, fail->config_error); + if (wpa_s->parent && wpa_s->parent != wpa_s) + wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL + "msg=%d config_error=%d", + fail->msg, fail->config_error); wpas_clear_wps(wpa_s); wpas_notify_wps_event_fail(wpa_s, fail); } @@ -407,6 +407,9 @@ 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; wpas_notify_wps_event_success(wpa_s); +#ifdef CONFIG_P2P + wpas_p2p_wps_success(wpa_s, wpa_s->bssid, 0); +#endif /* CONFIG_P2P */ } @@ -480,6 +483,32 @@ static void wpa_supplicant_wps_event_er_enrollee_remove( } +static void wpa_supplicant_wps_event_er_ap_settings( + struct wpa_supplicant *wpa_s, + struct wps_event_er_ap_settings *ap_settings) +{ + char uuid_str[100]; + char key_str[65]; + const struct wps_credential *cred = ap_settings->cred; + + key_str[0] = '\0'; + if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) { + if (cred->key_len >= 8 && cred->key_len <= 64) { + os_memcpy(key_str, cred->key, cred->key_len); + key_str[cred->key_len] = '\0'; + } + } + + uuid_bin2str(ap_settings->uuid, uuid_str, sizeof(uuid_str)); + /* Use wpa_msg_ctrl to avoid showing the key in debug log */ + wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_SETTINGS + "uuid=%s ssid=%s auth_type=0x%04x encr_type=0x%04x " + "key=%s", + uuid_str, wpa_ssid_txt(cred->ssid, cred->ssid_len), + cred->auth_type, cred->encr_type, key_str); +} + + static void wpa_supplicant_wps_event(void *ctx, enum wps_event event, union wps_event_data *data) { @@ -514,6 +543,10 @@ static void wpa_supplicant_wps_event(void *ctx, enum wps_event event, wpa_supplicant_wps_event_er_enrollee_remove(wpa_s, &data->enrollee); break; + case WPS_EV_ER_AP_SETTINGS: + wpa_supplicant_wps_event_er_ap_settings(wpa_s, + &data->ap_settings); + break; } } @@ -560,8 +593,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_INFO, WPS_EVENT_TIMEOUT "Requested operation timed " - "out"); + wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed " + "out"); wpas_clear_wps(wpa_s); } @@ -576,6 +609,7 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s, return NULL; wpas_notify_network_added(wpa_s, ssid); wpa_config_set_network_defaults(ssid); + ssid->temporary = 1; if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 || wpa_config_set(ssid, "eap", "WSC", 0) < 0 || wpa_config_set(ssid, "identity", registrar ? @@ -587,35 +621,44 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s, } if (bssid) { - size_t i; - struct wpa_scan_res *res; +#ifndef CONFIG_P2P + struct wpa_bss *bss; + int count = 0; +#endif /* CONFIG_P2P */ os_memcpy(ssid->bssid, bssid, ETH_ALEN); ssid->bssid_set = 1; - /* Try to get SSID from scan results */ - if (wpa_s->scan_res == NULL && - wpa_supplicant_get_scan_results(wpa_s) < 0) - return ssid; /* Could not find any scan results */ - - for (i = 0; i < wpa_s->scan_res->num; i++) { - const u8 *ie; - - res = wpa_s->scan_res->res[i]; - if (os_memcmp(bssid, res->bssid, ETH_ALEN) != 0) + /* + * Note: With P2P, the SSID may change at the time the WPS + * provisioning is started, so better not filter the AP based + * on the current SSID in the scan results. + */ +#ifndef CONFIG_P2P + dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { + if (os_memcmp(bssid, bss->bssid, ETH_ALEN) != 0) continue; - ie = wpa_scan_get_ie(res, WLAN_EID_SSID); - if (ie == NULL) - break; os_free(ssid->ssid); - ssid->ssid = os_malloc(ie[1]); + ssid->ssid = os_malloc(bss->ssid_len); if (ssid->ssid == NULL) break; - os_memcpy(ssid->ssid, ie + 2, ie[1]); - ssid->ssid_len = ie[1]; - break; + os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len); + ssid->ssid_len = bss->ssid_len; + wpa_hexdump_ascii(MSG_DEBUG, "WPS: Picked SSID from " + "scan results", + ssid->ssid, ssid->ssid_len); + count++; } + + if (count > 1) { + wpa_printf(MSG_DEBUG, "WPS: More than one SSID found " + "for the AP; use wildcard"); + os_free(ssid->ssid); + ssid->ssid = NULL; + ssid->ssid_len = 0; + } +#endif /* CONFIG_P2P */ } return ssid; @@ -645,14 +688,31 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s, } -int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid) +int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, + int p2p_group) { struct wpa_ssid *ssid; wpas_clear_wps(wpa_s); ssid = wpas_wps_add_network(wpa_s, 0, bssid); if (ssid == NULL) return -1; + ssid->temporary = 1; + ssid->p2p_group = p2p_group; +#ifdef CONFIG_P2P + if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) { + ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1); + if (ssid->ssid) { + ssid->ssid_len = wpa_s->go_params->ssid_len; + os_memcpy(ssid->ssid, wpa_s->go_params->ssid, + ssid->ssid_len); + wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP " + "SSID", ssid->ssid, ssid->ssid_len); + } + } +#endif /* CONFIG_P2P */ wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0); + if (wpa_s->wps_fragment_size) + ssid->eap.fragment_size = wpa_s->wps_fragment_size; eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, wpa_s, NULL); wpas_wps_reassoc(wpa_s, ssid); @@ -661,7 +721,7 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid) int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, - const char *pin) + const char *pin, int p2p_group, u16 dev_pw_id) { struct wpa_ssid *ssid; char val[128]; @@ -671,13 +731,31 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, ssid = wpas_wps_add_network(wpa_s, 0, bssid); if (ssid == NULL) return -1; + ssid->temporary = 1; + ssid->p2p_group = p2p_group; +#ifdef CONFIG_P2P + if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) { + ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1); + if (ssid->ssid) { + ssid->ssid_len = wpa_s->go_params->ssid_len; + os_memcpy(ssid->ssid, wpa_s->go_params->ssid, + ssid->ssid_len); + wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP " + "SSID", ssid->ssid, ssid->ssid_len); + } + } +#endif /* CONFIG_P2P */ if (pin) - os_snprintf(val, sizeof(val), "\"pin=%s\"", pin); + os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u\"", + pin, dev_pw_id); else { rpin = wps_generate_pin(); - os_snprintf(val, sizeof(val), "\"pin=%08d\"", rpin); + os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u\"", + rpin, dev_pw_id); } wpa_config_set(ssid, "phase1", val, 0); + if (wpa_s->wps_fragment_size) + ssid->eap.fragment_size = wpa_s->wps_fragment_size; eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, wpa_s, NULL); wpas_wps_reassoc(wpa_s, ssid); @@ -685,6 +763,32 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, } +/* Cancel the wps pbc/pin requests */ +int wpas_wps_cancel(struct wpa_supplicant *wpa_s) +{ +#ifdef CONFIG_AP + if (wpa_s->ap_iface) { + wpa_printf(MSG_DEBUG, "WPS: Cancelling in AP mode"); + return wpa_supplicant_ap_wps_cancel(wpa_s); + } +#endif /* CONFIG_AP */ + + if (wpa_s->wpa_state == WPA_SCANNING) { + wpa_printf(MSG_DEBUG, "WPS: Cancel operation - cancel scan"); + wpa_supplicant_cancel_scan(wpa_s); + wpas_clear_wps(wpa_s); + } else if (wpa_s->wpa_state >= WPA_ASSOCIATED) { + wpa_printf(MSG_DEBUG, "WPS: Cancel operation - " + "deauthenticate"); + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + wpas_clear_wps(wpa_s); + } + + return 0; +} + + #ifdef CONFIG_WPS_OOB int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type, char *path, char *method, char *name) @@ -727,7 +831,8 @@ int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type, if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E || wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) && wpas_wps_start_pin(wpa_s, NULL, - wpabuf_head(wps->oob_conf.dev_password)) < 0) + wpabuf_head(wps->oob_conf.dev_password), 0, + DEV_PW_DEFAULT) < 0) return -1; return 0; @@ -749,6 +854,7 @@ int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid, ssid = wpas_wps_add_network(wpa_s, 1, bssid); if (ssid == NULL) return -1; + ssid->temporary = 1; pos = val; end = pos + sizeof(val); res = os_snprintf(pos, end - pos, "\"pin=%s", pin); @@ -768,6 +874,8 @@ int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid, if (res < 0 || res >= end - pos) return -1; wpa_config_set(ssid, "phase1", val, 0); + if (wpa_s->wps_fragment_size) + ssid->eap.fragment_size = wpa_s->wps_fragment_size; eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, wpa_s, NULL); wpas_wps_reassoc(wpa_s, ssid); @@ -817,12 +925,38 @@ static void wpas_wps_set_sel_reg_cb(void *ctx, int sel_reg, u16 dev_passwd_id, if (wpa_s->wps_er == NULL) return; + wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar - sel_reg=%d " + "dev_password_id=%u sel_reg_config_methods=0x%x", + sel_reg, dev_passwd_id, sel_reg_config_methods); wps_er_set_sel_reg(wpa_s->wps_er, sel_reg, dev_passwd_id, sel_reg_config_methods); #endif /* CONFIG_WPS_ER */ } +static u16 wps_fix_config_methods(u16 config_methods) +{ +#ifdef CONFIG_WPS2 + if ((config_methods & + (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY | + WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) { + wpa_printf(MSG_INFO, "WPS: Converting display to " + "virtual_display for WPS 2.0 compliance"); + config_methods |= WPS_CONFIG_VIRT_DISPLAY; + } + if ((config_methods & + (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON | + WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) { + wpa_printf(MSG_INFO, "WPS: Converting push_button to " + "virtual_push_button for WPS 2.0 compliance"); + config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON; + } +#endif /* CONFIG_WPS2 */ + + return config_methods; +} + + int wpas_wps_init(struct wpa_supplicant *wpa_s) { struct wps_context *wps; @@ -841,6 +975,16 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s) wps->dev.model_name = wpa_s->conf->model_name; wps->dev.model_number = wpa_s->conf->model_number; wps->dev.serial_number = wpa_s->conf->serial_number; + wps->config_methods = + wps_config_methods_str2bin(wpa_s->conf->config_methods); + if ((wps->config_methods & (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) == + (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) { + wpa_printf(MSG_ERROR, "WPS: Both Label and Display config " + "methods are not allowed at the same time"); + os_free(wps); + return -1; + } + wps->config_methods = wps_fix_config_methods(wps->config_methods); if (wpa_s->conf->device_type && wps_dev_type_str2bin(wpa_s->conf->device_type, wps->dev.pri_dev_type) < 0) { @@ -888,7 +1032,7 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s) return; #ifdef CONFIG_WPS_ER - wps_er_deinit(wpa_s->wps_er); + wps_er_deinit(wpa_s->wps_er, NULL, NULL); wpa_s->wps_er = NULL; #endif /* CONFIG_WPS_ER */ @@ -939,12 +1083,13 @@ int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s, } /* - * 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. + * Start with WPS APs that advertise our address as an + * authorized MAC (v2.0) or active PIN Registrar (v1.0) and + * allow any WPS AP after couple of scans since some APs do not + * set Selected Registrar attribute properly when using + * external Registrar. */ - if (!wps_is_selected_pin_registrar(wps_ie)) { + if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) { if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) { wpa_printf(MSG_DEBUG, " skip - WPS AP " "without active PIN Registrar"); @@ -954,7 +1099,7 @@ int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, " selected based on WPS IE"); } else { wpa_printf(MSG_DEBUG, " selected based on WPS IE " - "(Active PIN)"); + "(Authorized MAC or Active PIN)"); } wpabuf_free(wps_ie); return 1; @@ -986,7 +1131,7 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, } 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) || + (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1) || wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) { /* allow wildcard SSID for WPS PIN */ ret = 1; @@ -999,6 +1144,28 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, ret = 1; } +#ifdef CONFIG_WPS_STRICT + if (wps_ie) { + if (wps_validate_beacon_probe_resp(wps_ie, bss->beacon_ie_len > + 0, bss->bssid) < 0) + ret = 0; + if (bss->beacon_ie_len) { + struct wpabuf *bcn_wps; + bcn_wps = wpa_scan_get_vendor_ie_multi_beacon( + bss, WPS_IE_VENDOR_TYPE); + if (bcn_wps == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Mandatory WPS IE " + "missing from AP Beacon"); + ret = 0; + } else { + if (wps_validate_beacon(wps_ie) < 0) + ret = 0; + wpabuf_free(bcn_wps); + } + } + } +#endif /* CONFIG_WPS_STRICT */ + wpabuf_free(wps_ie); return ret; @@ -1006,40 +1173,55 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, - struct wpa_scan_res *selected, - struct wpa_ssid *ssid) + struct wpa_bss *selected, struct wpa_ssid *ssid) { const u8 *sel_uuid, *uuid; - size_t i; struct wpabuf *wps_ie; int ret = 0; + struct wpa_bss *bss; if (!eap_is_wps_pbc_enrollee(&ssid->eap)) return 0; + wpa_printf(MSG_DEBUG, "WPS: Check whether PBC session overlap is " + "present in scan results; selected BSSID " MACSTR, + MAC2STR(selected->bssid)); + /* Make sure that only one AP is in active PBC mode */ - wps_ie = wpa_scan_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE); - if (wps_ie) + wps_ie = wpa_bss_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE); + if (wps_ie) { sel_uuid = wps_get_uuid_e(wps_ie); - else + wpa_hexdump(MSG_DEBUG, "WPS: UUID of the selected BSS", + sel_uuid, UUID_LEN); + } else { + wpa_printf(MSG_DEBUG, "WPS: Selected BSS does not include " + "WPS IE?!"); sel_uuid = NULL; + } - for (i = 0; i < wpa_s->scan_res->num; i++) { - struct wpa_scan_res *bss = wpa_s->scan_res->res[i]; + dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { struct wpabuf *ie; if (bss == selected) continue; - ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); if (!ie) continue; if (!wps_is_selected_pbc_registrar(ie)) { wpabuf_free(ie); continue; } + wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: " + MACSTR, MAC2STR(bss->bssid)); uuid = wps_get_uuid_e(ie); + wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS", + uuid, UUID_LEN); if (sel_uuid == NULL || uuid == NULL || - os_memcmp(sel_uuid, uuid, 16) != 0) { + os_memcmp(sel_uuid, uuid, UUID_LEN) != 0) { ret = 1; /* PBC overlap */ + wpa_msg(wpa_s, MSG_INFO, "WPS: PBC overlap detected: " + MACSTR " and " MACSTR, + MAC2STR(selected->bssid), + MAC2STR(bss->bssid)); wpabuf_free(ie); break; } @@ -1057,23 +1239,28 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s) { - size_t i; + struct wpa_bss *bss; if (wpa_s->disconnected || wpa_s->wpa_state >= WPA_ASSOCIATED) return; - for (i = 0; i < wpa_s->scan_res->num; i++) { - struct wpa_scan_res *bss = wpa_s->scan_res->res[i]; + dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { struct wpabuf *ie; - ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); if (!ie) continue; if (wps_is_selected_pbc_registrar(ie)) - wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PBC); + wpa_msg_ctrl(wpa_s, MSG_INFO, + WPS_EVENT_AP_AVAILABLE_PBC); + else if (wps_is_addr_authorized(ie, wpa_s->own_addr, 0)) + wpa_msg_ctrl(wpa_s, MSG_INFO, + WPS_EVENT_AP_AVAILABLE_AUTH); else if (wps_is_selected_pin_registrar(ie)) - wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PIN); + wpa_msg_ctrl(wpa_s, MSG_INFO, + WPS_EVENT_AP_AVAILABLE_PIN); else - wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE); + wpa_msg_ctrl(wpa_s, MSG_INFO, + WPS_EVENT_AP_AVAILABLE); wpabuf_free(ie); break; } @@ -1109,14 +1296,14 @@ int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *buf, } -int wpas_wps_er_start(struct wpa_supplicant *wpa_s) +int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter) { #ifdef CONFIG_WPS_ER if (wpa_s->wps_er) { wps_er_refresh(wpa_s->wps_er); return 0; } - wpa_s->wps_er = wps_er_init(wpa_s->wps, wpa_s->ifname); + wpa_s->wps_er = wps_er_init(wpa_s->wps, wpa_s->ifname, filter); if (wpa_s->wps_er == NULL) return -1; return 0; @@ -1129,7 +1316,7 @@ int wpas_wps_er_start(struct wpa_supplicant *wpa_s) int wpas_wps_er_stop(struct wpa_supplicant *wpa_s) { #ifdef CONFIG_WPS_ER - wps_er_deinit(wpa_s->wps_er); + wps_er_deinit(wpa_s->wps_er, NULL, NULL); wpa_s->wps_er = NULL; #endif /* CONFIG_WPS_ER */ return 0; @@ -1137,8 +1324,8 @@ int wpas_wps_er_stop(struct wpa_supplicant *wpa_s) #ifdef CONFIG_WPS_ER -int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const char *uuid, - const char *pin) +int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr, + const char *uuid, const char *pin) { u8 u[UUID_LEN]; int any = 0; @@ -1147,7 +1334,8 @@ int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const char *uuid, any = 1; else if (uuid_str2bin(uuid, u)) return -1; - return wps_registrar_add_pin(wpa_s->wps->registrar, any ? NULL : u, + return wps_registrar_add_pin(wpa_s->wps->registrar, addr, + any ? NULL : u, (const u8 *) pin, os_strlen(pin), 300); } @@ -1172,4 +1360,140 @@ int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid, return wps_er_learn(wpa_s->wps_er, u, (const u8 *) pin, os_strlen(pin)); } + + +int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid, + const char *pin, struct wps_new_ap_settings *settings) +{ + u8 u[UUID_LEN]; + struct wps_credential cred; + size_t len; + + if (uuid_str2bin(uuid, u)) + return -1; + if (settings->ssid_hex == NULL || settings->auth == NULL || + settings->encr == NULL || settings->key_hex == NULL) + return -1; + + os_memset(&cred, 0, sizeof(cred)); + len = os_strlen(settings->ssid_hex); + if ((len & 1) || len > 2 * sizeof(cred.ssid) || + hexstr2bin(settings->ssid_hex, cred.ssid, len / 2)) + return -1; + cred.ssid_len = len / 2; + + len = os_strlen(settings->key_hex); + if ((len & 1) || len > 2 * sizeof(cred.key) || + hexstr2bin(settings->key_hex, cred.key, len / 2)) + return -1; + cred.key_len = len / 2; + + if (os_strcmp(settings->auth, "OPEN") == 0) + cred.auth_type = WPS_AUTH_OPEN; + else if (os_strcmp(settings->auth, "WPAPSK") == 0) + cred.auth_type = WPS_AUTH_WPAPSK; + else if (os_strcmp(settings->auth, "WPA2PSK") == 0) + cred.auth_type = WPS_AUTH_WPA2PSK; + else + return -1; + + if (os_strcmp(settings->encr, "NONE") == 0) + cred.encr_type = WPS_ENCR_NONE; + else if (os_strcmp(settings->encr, "WEP") == 0) + cred.encr_type = WPS_ENCR_WEP; + else if (os_strcmp(settings->encr, "TKIP") == 0) + cred.encr_type = WPS_ENCR_TKIP; + else if (os_strcmp(settings->encr, "CCMP") == 0) + cred.encr_type = WPS_ENCR_AES; + else + return -1; + + return wps_er_config(wpa_s->wps_er, u, (const u8 *) pin, + os_strlen(pin), &cred); +} + + +static void wpas_wps_terminate_cb(void *ctx) +{ + wpa_printf(MSG_DEBUG, "WPS ER: Terminated"); + eloop_terminate(); +} +#endif /* CONFIG_WPS_ER */ + + +int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s) +{ +#ifdef CONFIG_WPS_ER + if (wpa_s->wps_er) { + wps_er_deinit(wpa_s->wps_er, wpas_wps_terminate_cb, wpa_s); + wpa_s->wps_er = NULL; + return 1; + } #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; +} + + +void wpas_wps_update_config(struct wpa_supplicant *wpa_s) +{ + struct wps_context *wps = wpa_s->wps; + + if (wps == NULL) + return; + + if (wpa_s->conf->changed_parameters & CFG_CHANGED_CONFIG_METHODS) { + wps->config_methods = wps_config_methods_str2bin( + wpa_s->conf->config_methods); + if ((wps->config_methods & + (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) == + (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) { + wpa_printf(MSG_ERROR, "WPS: Both Label and Display " + "config methods are not allowed at the " + "same time"); + wps->config_methods &= ~WPS_CONFIG_LABEL; + } + } + wps->config_methods = wps_fix_config_methods(wps->config_methods); + + if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE) { + if (wpa_s->conf->device_type && + wps_dev_type_str2bin(wpa_s->conf->device_type, + wps->dev.pri_dev_type) < 0) + wpa_printf(MSG_ERROR, "WPS: Invalid device_type"); + } + + if (wpa_s->conf->changed_parameters & CFG_CHANGED_OS_VERSION) + wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version); + + if (wpa_s->conf->changed_parameters & CFG_CHANGED_UUID) { + if (is_nil_uuid(wpa_s->conf->uuid)) { + uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid); + wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC " + "address", wps->uuid, WPS_UUID_LEN); + } else + os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN); + } + + if (wpa_s->conf->changed_parameters & + (CFG_CHANGED_DEVICE_NAME | CFG_CHANGED_WPS_STRING)) { + /* Update pointers to make sure they refer current values */ + wps->dev.device_name = wpa_s->conf->device_name; + wps->dev.manufacturer = wpa_s->conf->manufacturer; + wps->dev.model_name = wpa_s->conf->model_name; + wps->dev.model_number = wpa_s->conf->model_number; + wps->dev.serial_number = wpa_s->conf->serial_number; + } +}