139beb93cSSam Leffler /* 239beb93cSSam Leffler * wpa_supplicant / WPS integration 3*f05cddf9SRui Paulo * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5*f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6*f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 1139beb93cSSam Leffler #include "common.h" 1239beb93cSSam Leffler #include "eloop.h" 1339beb93cSSam Leffler #include "uuid.h" 14*f05cddf9SRui Paulo #include "crypto/random.h" 15e28a4053SRui Paulo #include "crypto/dh_group5.h" 16e28a4053SRui Paulo #include "common/ieee802_11_defs.h" 17e28a4053SRui Paulo #include "common/ieee802_11_common.h" 18e28a4053SRui Paulo #include "common/wpa_common.h" 19e28a4053SRui Paulo #include "common/wpa_ctrl.h" 2039beb93cSSam Leffler #include "eap_common/eap_wsc_common.h" 21e28a4053SRui Paulo #include "eap_peer/eap.h" 22*f05cddf9SRui Paulo #include "eapol_supp/eapol_supp_sm.h" 23e28a4053SRui Paulo #include "rsn_supp/wpa.h" 24*f05cddf9SRui Paulo #include "wps/wps_attr_parse.h" 25e28a4053SRui Paulo #include "config.h" 26e28a4053SRui Paulo #include "wpa_supplicant_i.h" 27e28a4053SRui Paulo #include "driver_i.h" 28e28a4053SRui Paulo #include "notify.h" 2939beb93cSSam Leffler #include "blacklist.h" 30e28a4053SRui Paulo #include "bss.h" 31e28a4053SRui Paulo #include "scan.h" 32*f05cddf9SRui Paulo #include "ap.h" 33*f05cddf9SRui Paulo #include "p2p/p2p.h" 34*f05cddf9SRui Paulo #include "p2p_supplicant.h" 3539beb93cSSam Leffler #include "wps_supplicant.h" 3639beb93cSSam Leffler 373157ba21SRui Paulo 38*f05cddf9SRui Paulo #ifndef WPS_PIN_SCAN_IGNORE_SEL_REG 3939beb93cSSam Leffler #define WPS_PIN_SCAN_IGNORE_SEL_REG 3 40*f05cddf9SRui Paulo #endif /* WPS_PIN_SCAN_IGNORE_SEL_REG */ 4139beb93cSSam Leffler 4239beb93cSSam Leffler static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx); 4339beb93cSSam Leffler static void wpas_clear_wps(struct wpa_supplicant *wpa_s); 4439beb93cSSam Leffler 4539beb93cSSam Leffler 46*f05cddf9SRui Paulo static void wpas_wps_clear_ap_info(struct wpa_supplicant *wpa_s) 47*f05cddf9SRui Paulo { 48*f05cddf9SRui Paulo os_free(wpa_s->wps_ap); 49*f05cddf9SRui Paulo wpa_s->wps_ap = NULL; 50*f05cddf9SRui Paulo wpa_s->num_wps_ap = 0; 51*f05cddf9SRui Paulo wpa_s->wps_ap_iter = 0; 52*f05cddf9SRui Paulo } 53*f05cddf9SRui Paulo 54*f05cddf9SRui Paulo 5539beb93cSSam Leffler int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) 5639beb93cSSam Leffler { 5739beb93cSSam Leffler if (!wpa_s->wps_success && 5839beb93cSSam Leffler wpa_s->current_ssid && 5939beb93cSSam Leffler eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) { 6039beb93cSSam Leffler const u8 *bssid = wpa_s->bssid; 6139beb93cSSam Leffler if (is_zero_ether_addr(bssid)) 6239beb93cSSam Leffler bssid = wpa_s->pending_bssid; 6339beb93cSSam Leffler 6439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: PIN registration with " MACSTR 6539beb93cSSam Leffler " did not succeed - continue trying to find " 6639beb93cSSam Leffler "suitable AP", MAC2STR(bssid)); 6739beb93cSSam Leffler wpa_blacklist_add(wpa_s, bssid); 6839beb93cSSam Leffler 6939beb93cSSam Leffler wpa_supplicant_deauthenticate(wpa_s, 7039beb93cSSam Leffler WLAN_REASON_DEAUTH_LEAVING); 7139beb93cSSam Leffler wpa_s->reassociate = 1; 7239beb93cSSam Leffler wpa_supplicant_req_scan(wpa_s, 7339beb93cSSam Leffler wpa_s->blacklist_cleared ? 5 : 0, 0); 7439beb93cSSam Leffler wpa_s->blacklist_cleared = 0; 7539beb93cSSam Leffler return 1; 7639beb93cSSam Leffler } 7739beb93cSSam Leffler 78*f05cddf9SRui Paulo wpas_wps_clear_ap_info(wpa_s); 7939beb93cSSam Leffler eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL); 80*f05cddf9SRui Paulo if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && !wpa_s->wps_success) 81*f05cddf9SRui Paulo wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL); 8239beb93cSSam Leffler 8339beb93cSSam Leffler if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid && 8439beb93cSSam Leffler !(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) { 85*f05cddf9SRui Paulo int disabled = wpa_s->current_ssid->disabled; 86*f05cddf9SRui Paulo unsigned int freq = wpa_s->assoc_freq; 8739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - " 88*f05cddf9SRui Paulo "try to associate with the received credential " 89*f05cddf9SRui Paulo "(freq=%u)", freq); 9039beb93cSSam Leffler wpa_supplicant_deauthenticate(wpa_s, 9139beb93cSSam Leffler WLAN_REASON_DEAUTH_LEAVING); 92*f05cddf9SRui Paulo if (disabled) { 93*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Current network is " 94*f05cddf9SRui Paulo "disabled - wait for user to enable"); 95*f05cddf9SRui Paulo return 1; 96*f05cddf9SRui Paulo } 97e28a4053SRui Paulo wpa_s->after_wps = 5; 98*f05cddf9SRui Paulo wpa_s->wps_freq = freq; 99*f05cddf9SRui Paulo wpa_s->normal_scans = 0; 10039beb93cSSam Leffler wpa_s->reassociate = 1; 10139beb93cSSam Leffler wpa_supplicant_req_scan(wpa_s, 0, 0); 10239beb93cSSam Leffler return 1; 10339beb93cSSam Leffler } 10439beb93cSSam Leffler 10539beb93cSSam Leffler if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid) { 10639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting " 10739beb93cSSam Leffler "for external credential processing"); 10839beb93cSSam Leffler wpas_clear_wps(wpa_s); 10939beb93cSSam Leffler wpa_supplicant_deauthenticate(wpa_s, 11039beb93cSSam Leffler WLAN_REASON_DEAUTH_LEAVING); 11139beb93cSSam Leffler return 1; 11239beb93cSSam Leffler } 11339beb93cSSam Leffler 11439beb93cSSam Leffler return 0; 11539beb93cSSam Leffler } 11639beb93cSSam Leffler 11739beb93cSSam Leffler 1183157ba21SRui Paulo static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s, 1193157ba21SRui Paulo struct wpa_ssid *ssid, 1203157ba21SRui Paulo const struct wps_credential *cred) 1213157ba21SRui Paulo { 1223157ba21SRui Paulo struct wpa_driver_capa capa; 123e28a4053SRui Paulo struct wpa_bss *bss; 1243157ba21SRui Paulo const u8 *ie; 1253157ba21SRui Paulo struct wpa_ie_data adv; 1263157ba21SRui Paulo int wpa2 = 0, ccmp = 0; 1273157ba21SRui Paulo 1283157ba21SRui Paulo /* 1293157ba21SRui Paulo * Many existing WPS APs do not know how to negotiate WPA2 or CCMP in 1303157ba21SRui Paulo * case they are configured for mixed mode operation (WPA+WPA2 and 1313157ba21SRui Paulo * TKIP+CCMP). Try to use scan results to figure out whether the AP 1323157ba21SRui Paulo * actually supports stronger security and select that if the client 1333157ba21SRui Paulo * has support for it, too. 1343157ba21SRui Paulo */ 1353157ba21SRui Paulo 1363157ba21SRui Paulo if (wpa_drv_get_capa(wpa_s, &capa)) 1373157ba21SRui Paulo return; /* Unknown what driver supports */ 1383157ba21SRui Paulo 139*f05cddf9SRui Paulo if (ssid->ssid == NULL) 140*f05cddf9SRui Paulo return; 141e28a4053SRui Paulo bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len); 142e28a4053SRui Paulo if (bss == NULL) { 143e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS " 144e28a4053SRui Paulo "table - use credential as-is"); 1453157ba21SRui Paulo return; 1463157ba21SRui Paulo } 1473157ba21SRui Paulo 148e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: AP found from BSS table"); 149e28a4053SRui Paulo 150e28a4053SRui Paulo ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); 1513157ba21SRui Paulo if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0) { 1523157ba21SRui Paulo wpa2 = 1; 1533157ba21SRui Paulo if (adv.pairwise_cipher & WPA_CIPHER_CCMP) 1543157ba21SRui Paulo ccmp = 1; 1553157ba21SRui Paulo } else { 156e28a4053SRui Paulo ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); 1573157ba21SRui Paulo if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0 && 1583157ba21SRui Paulo adv.pairwise_cipher & WPA_CIPHER_CCMP) 1593157ba21SRui Paulo ccmp = 1; 1603157ba21SRui Paulo } 1613157ba21SRui Paulo 1623157ba21SRui Paulo if (ie == NULL && (ssid->proto & WPA_PROTO_WPA) && 1633157ba21SRui Paulo (ssid->pairwise_cipher & WPA_CIPHER_TKIP)) { 1643157ba21SRui Paulo /* 1653157ba21SRui Paulo * TODO: This could be the initial AP configuration and the 1663157ba21SRui Paulo * Beacon contents could change shortly. Should request a new 1673157ba21SRui Paulo * scan and delay addition of the network until the updated 1683157ba21SRui Paulo * scan results are available. 1693157ba21SRui Paulo */ 1703157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: The AP did not yet advertise WPA " 1713157ba21SRui Paulo "support - use credential as-is"); 1723157ba21SRui Paulo return; 1733157ba21SRui Paulo } 1743157ba21SRui Paulo 1753157ba21SRui Paulo if (ccmp && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) && 1763157ba21SRui Paulo (ssid->pairwise_cipher & WPA_CIPHER_TKIP) && 1773157ba21SRui Paulo (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { 1783157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Add CCMP into the credential " 1793157ba21SRui Paulo "based on scan results"); 1803157ba21SRui Paulo if (wpa_s->conf->ap_scan == 1) 1813157ba21SRui Paulo ssid->pairwise_cipher |= WPA_CIPHER_CCMP; 1823157ba21SRui Paulo else 1833157ba21SRui Paulo ssid->pairwise_cipher = WPA_CIPHER_CCMP; 1843157ba21SRui Paulo } 1853157ba21SRui Paulo 1863157ba21SRui Paulo if (wpa2 && !(ssid->proto & WPA_PROTO_RSN) && 1873157ba21SRui Paulo (ssid->proto & WPA_PROTO_WPA) && 1883157ba21SRui Paulo (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP)) { 1893157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Add WPA2 into the credential " 1903157ba21SRui Paulo "based on scan results"); 1913157ba21SRui Paulo if (wpa_s->conf->ap_scan == 1) 1923157ba21SRui Paulo ssid->proto |= WPA_PROTO_RSN; 1933157ba21SRui Paulo else 1943157ba21SRui Paulo ssid->proto = WPA_PROTO_RSN; 1953157ba21SRui Paulo } 1963157ba21SRui Paulo } 1973157ba21SRui Paulo 1983157ba21SRui Paulo 19939beb93cSSam Leffler static int wpa_supplicant_wps_cred(void *ctx, 20039beb93cSSam Leffler const struct wps_credential *cred) 20139beb93cSSam Leffler { 20239beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 20339beb93cSSam Leffler struct wpa_ssid *ssid = wpa_s->current_ssid; 2043157ba21SRui Paulo u8 key_idx = 0; 2053157ba21SRui Paulo u16 auth_type; 206*f05cddf9SRui Paulo #ifdef CONFIG_WPS_REG_DISABLE_OPEN 207*f05cddf9SRui Paulo int registrar = 0; 208*f05cddf9SRui Paulo #endif /* CONFIG_WPS_REG_DISABLE_OPEN */ 20939beb93cSSam Leffler 21039beb93cSSam Leffler if ((wpa_s->conf->wps_cred_processing == 1 || 21139beb93cSSam Leffler wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) { 21239beb93cSSam Leffler size_t blen = cred->cred_attr_len * 2 + 1; 21339beb93cSSam Leffler char *buf = os_malloc(blen); 21439beb93cSSam Leffler if (buf) { 21539beb93cSSam Leffler wpa_snprintf_hex(buf, blen, 21639beb93cSSam Leffler cred->cred_attr, cred->cred_attr_len); 21739beb93cSSam Leffler wpa_msg(wpa_s, MSG_INFO, "%s%s", 21839beb93cSSam Leffler WPS_EVENT_CRED_RECEIVED, buf); 21939beb93cSSam Leffler os_free(buf); 22039beb93cSSam Leffler } 221e28a4053SRui Paulo 222e28a4053SRui Paulo wpas_notify_wps_credential(wpa_s, cred); 22339beb93cSSam Leffler } else 22439beb93cSSam Leffler wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED); 22539beb93cSSam Leffler 22639beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute", 22739beb93cSSam Leffler cred->cred_attr, cred->cred_attr_len); 22839beb93cSSam Leffler 22939beb93cSSam Leffler if (wpa_s->conf->wps_cred_processing == 1) 23039beb93cSSam Leffler return 0; 23139beb93cSSam Leffler 2323157ba21SRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len); 2333157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x", 23439beb93cSSam Leffler cred->auth_type); 2353157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type); 2363157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx); 2373157ba21SRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", 2383157ba21SRui Paulo cred->key, cred->key_len); 2393157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, 2403157ba21SRui Paulo MAC2STR(cred->mac_addr)); 2413157ba21SRui Paulo 2423157ba21SRui Paulo auth_type = cred->auth_type; 2433157ba21SRui Paulo if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) { 2443157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Workaround - convert mixed-mode " 2453157ba21SRui Paulo "auth_type into WPA2PSK"); 2463157ba21SRui Paulo auth_type = WPS_AUTH_WPA2PSK; 2473157ba21SRui Paulo } 2483157ba21SRui Paulo 2493157ba21SRui Paulo if (auth_type != WPS_AUTH_OPEN && 2503157ba21SRui Paulo auth_type != WPS_AUTH_SHARED && 2513157ba21SRui Paulo auth_type != WPS_AUTH_WPAPSK && 2523157ba21SRui Paulo auth_type != WPS_AUTH_WPA2PSK) { 2533157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for " 2543157ba21SRui Paulo "unsupported authentication type 0x%x", 2553157ba21SRui Paulo auth_type); 25639beb93cSSam Leffler return 0; 25739beb93cSSam Leffler } 25839beb93cSSam Leffler 259*f05cddf9SRui Paulo if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) { 260*f05cddf9SRui Paulo if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) { 261*f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with " 262*f05cddf9SRui Paulo "invalid Network Key length %lu", 263*f05cddf9SRui Paulo (unsigned long) cred->key_len); 264*f05cddf9SRui Paulo return -1; 265*f05cddf9SRui Paulo } 266*f05cddf9SRui Paulo } 267*f05cddf9SRui Paulo 26839beb93cSSam Leffler if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) { 26939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based " 27039beb93cSSam Leffler "on the received credential"); 271*f05cddf9SRui Paulo #ifdef CONFIG_WPS_REG_DISABLE_OPEN 272*f05cddf9SRui Paulo if (ssid->eap.identity && 273*f05cddf9SRui Paulo ssid->eap.identity_len == WSC_ID_REGISTRAR_LEN && 274*f05cddf9SRui Paulo os_memcmp(ssid->eap.identity, WSC_ID_REGISTRAR, 275*f05cddf9SRui Paulo WSC_ID_REGISTRAR_LEN) == 0) 276*f05cddf9SRui Paulo registrar = 1; 277*f05cddf9SRui Paulo #endif /* CONFIG_WPS_REG_DISABLE_OPEN */ 27839beb93cSSam Leffler os_free(ssid->eap.identity); 27939beb93cSSam Leffler ssid->eap.identity = NULL; 28039beb93cSSam Leffler ssid->eap.identity_len = 0; 28139beb93cSSam Leffler os_free(ssid->eap.phase1); 28239beb93cSSam Leffler ssid->eap.phase1 = NULL; 28339beb93cSSam Leffler os_free(ssid->eap.eap_methods); 28439beb93cSSam Leffler ssid->eap.eap_methods = NULL; 285*f05cddf9SRui Paulo if (!ssid->p2p_group) { 286*f05cddf9SRui Paulo ssid->temporary = 0; 287*f05cddf9SRui Paulo ssid->bssid_set = 0; 288*f05cddf9SRui Paulo } 289*f05cddf9SRui Paulo ssid->disabled_until.sec = 0; 290*f05cddf9SRui Paulo ssid->disabled_until.usec = 0; 291*f05cddf9SRui Paulo ssid->auth_failures = 0; 29239beb93cSSam Leffler } else { 29339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the " 29439beb93cSSam Leffler "received credential"); 29539beb93cSSam Leffler ssid = wpa_config_add_network(wpa_s->conf); 29639beb93cSSam Leffler if (ssid == NULL) 29739beb93cSSam Leffler return -1; 298e28a4053SRui Paulo wpas_notify_network_added(wpa_s, ssid); 29939beb93cSSam Leffler } 30039beb93cSSam Leffler 30139beb93cSSam Leffler wpa_config_set_network_defaults(ssid); 30239beb93cSSam Leffler 30339beb93cSSam Leffler os_free(ssid->ssid); 30439beb93cSSam Leffler ssid->ssid = os_malloc(cred->ssid_len); 30539beb93cSSam Leffler if (ssid->ssid) { 30639beb93cSSam Leffler os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len); 30739beb93cSSam Leffler ssid->ssid_len = cred->ssid_len; 30839beb93cSSam Leffler } 30939beb93cSSam Leffler 31039beb93cSSam Leffler switch (cred->encr_type) { 31139beb93cSSam Leffler case WPS_ENCR_NONE: 31239beb93cSSam Leffler break; 31339beb93cSSam Leffler case WPS_ENCR_WEP: 3143157ba21SRui Paulo if (cred->key_len <= 0) 3153157ba21SRui Paulo break; 3163157ba21SRui Paulo if (cred->key_len != 5 && cred->key_len != 13 && 3173157ba21SRui Paulo cred->key_len != 10 && cred->key_len != 26) { 3183157ba21SRui Paulo wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key length " 3193157ba21SRui Paulo "%lu", (unsigned long) cred->key_len); 3203157ba21SRui Paulo return -1; 32139beb93cSSam Leffler } 3223157ba21SRui Paulo if (cred->key_idx > NUM_WEP_KEYS) { 3233157ba21SRui Paulo wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key index %d", 3243157ba21SRui Paulo cred->key_idx); 3253157ba21SRui Paulo return -1; 3263157ba21SRui Paulo } 3273157ba21SRui Paulo if (cred->key_idx) 3283157ba21SRui Paulo key_idx = cred->key_idx - 1; 3293157ba21SRui Paulo if (cred->key_len == 10 || cred->key_len == 26) { 3303157ba21SRui Paulo if (hexstr2bin((char *) cred->key, 3313157ba21SRui Paulo ssid->wep_key[key_idx], 3323157ba21SRui Paulo cred->key_len / 2) < 0) { 3333157ba21SRui Paulo wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key " 3343157ba21SRui Paulo "%d", key_idx); 3353157ba21SRui Paulo return -1; 3363157ba21SRui Paulo } 3373157ba21SRui Paulo ssid->wep_key_len[key_idx] = cred->key_len / 2; 3383157ba21SRui Paulo } else { 3393157ba21SRui Paulo os_memcpy(ssid->wep_key[key_idx], cred->key, 3403157ba21SRui Paulo cred->key_len); 3413157ba21SRui Paulo ssid->wep_key_len[key_idx] = cred->key_len; 3423157ba21SRui Paulo } 3433157ba21SRui Paulo ssid->wep_tx_keyidx = key_idx; 34439beb93cSSam Leffler break; 34539beb93cSSam Leffler case WPS_ENCR_TKIP: 34639beb93cSSam Leffler ssid->pairwise_cipher = WPA_CIPHER_TKIP; 34739beb93cSSam Leffler break; 34839beb93cSSam Leffler case WPS_ENCR_AES: 34939beb93cSSam Leffler ssid->pairwise_cipher = WPA_CIPHER_CCMP; 35039beb93cSSam Leffler break; 35139beb93cSSam Leffler } 35239beb93cSSam Leffler 3533157ba21SRui Paulo switch (auth_type) { 35439beb93cSSam Leffler case WPS_AUTH_OPEN: 35539beb93cSSam Leffler ssid->auth_alg = WPA_AUTH_ALG_OPEN; 35639beb93cSSam Leffler ssid->key_mgmt = WPA_KEY_MGMT_NONE; 35739beb93cSSam Leffler ssid->proto = 0; 358*f05cddf9SRui Paulo #ifdef CONFIG_WPS_REG_DISABLE_OPEN 359*f05cddf9SRui Paulo if (registrar) { 360*f05cddf9SRui Paulo wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OPEN_NETWORK 361*f05cddf9SRui Paulo "id=%d - Credentials for an open " 362*f05cddf9SRui Paulo "network disabled by default - use " 363*f05cddf9SRui Paulo "'select_network %d' to enable", 364*f05cddf9SRui Paulo ssid->id, ssid->id); 365*f05cddf9SRui Paulo ssid->disabled = 1; 366*f05cddf9SRui Paulo } 367*f05cddf9SRui Paulo #endif /* CONFIG_WPS_REG_DISABLE_OPEN */ 36839beb93cSSam Leffler break; 36939beb93cSSam Leffler case WPS_AUTH_SHARED: 37039beb93cSSam Leffler ssid->auth_alg = WPA_AUTH_ALG_SHARED; 37139beb93cSSam Leffler ssid->key_mgmt = WPA_KEY_MGMT_NONE; 37239beb93cSSam Leffler ssid->proto = 0; 37339beb93cSSam Leffler break; 37439beb93cSSam Leffler case WPS_AUTH_WPAPSK: 37539beb93cSSam Leffler ssid->auth_alg = WPA_AUTH_ALG_OPEN; 37639beb93cSSam Leffler ssid->key_mgmt = WPA_KEY_MGMT_PSK; 37739beb93cSSam Leffler ssid->proto = WPA_PROTO_WPA; 37839beb93cSSam Leffler break; 37939beb93cSSam Leffler case WPS_AUTH_WPA2PSK: 38039beb93cSSam Leffler ssid->auth_alg = WPA_AUTH_ALG_OPEN; 38139beb93cSSam Leffler ssid->key_mgmt = WPA_KEY_MGMT_PSK; 38239beb93cSSam Leffler ssid->proto = WPA_PROTO_RSN; 38339beb93cSSam Leffler break; 38439beb93cSSam Leffler } 38539beb93cSSam Leffler 38639beb93cSSam Leffler if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) { 38739beb93cSSam Leffler if (cred->key_len == 2 * PMK_LEN) { 38839beb93cSSam Leffler if (hexstr2bin((const char *) cred->key, ssid->psk, 38939beb93cSSam Leffler PMK_LEN)) { 39039beb93cSSam Leffler wpa_printf(MSG_ERROR, "WPS: Invalid Network " 39139beb93cSSam Leffler "Key"); 39239beb93cSSam Leffler return -1; 39339beb93cSSam Leffler } 39439beb93cSSam Leffler ssid->psk_set = 1; 395*f05cddf9SRui Paulo ssid->export_keys = 1; 39639beb93cSSam Leffler } else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) { 39739beb93cSSam Leffler os_free(ssid->passphrase); 39839beb93cSSam Leffler ssid->passphrase = os_malloc(cred->key_len + 1); 39939beb93cSSam Leffler if (ssid->passphrase == NULL) 40039beb93cSSam Leffler return -1; 40139beb93cSSam Leffler os_memcpy(ssid->passphrase, cred->key, cred->key_len); 40239beb93cSSam Leffler ssid->passphrase[cred->key_len] = '\0'; 40339beb93cSSam Leffler wpa_config_update_psk(ssid); 404*f05cddf9SRui Paulo ssid->export_keys = 1; 40539beb93cSSam Leffler } else { 40639beb93cSSam Leffler wpa_printf(MSG_ERROR, "WPS: Invalid Network Key " 40739beb93cSSam Leffler "length %lu", 40839beb93cSSam Leffler (unsigned long) cred->key_len); 40939beb93cSSam Leffler return -1; 41039beb93cSSam Leffler } 41139beb93cSSam Leffler } 41239beb93cSSam Leffler 4133157ba21SRui Paulo wpas_wps_security_workaround(wpa_s, ssid, cred); 4143157ba21SRui Paulo 415*f05cddf9SRui Paulo if (cred->ap_channel) 416*f05cddf9SRui Paulo wpa_s->wps_ap_channel = cred->ap_channel; 417*f05cddf9SRui Paulo 41839beb93cSSam Leffler #ifndef CONFIG_NO_CONFIG_WRITE 41939beb93cSSam Leffler if (wpa_s->conf->update_config && 42039beb93cSSam Leffler wpa_config_write(wpa_s->confname, wpa_s->conf)) { 42139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration"); 42239beb93cSSam Leffler return -1; 42339beb93cSSam Leffler } 42439beb93cSSam Leffler #endif /* CONFIG_NO_CONFIG_WRITE */ 42539beb93cSSam Leffler 426*f05cddf9SRui Paulo /* 427*f05cddf9SRui Paulo * Optimize the post-WPS scan based on the channel used during 428*f05cddf9SRui Paulo * the provisioning in case EAP-Failure is not received. 429*f05cddf9SRui Paulo */ 430*f05cddf9SRui Paulo wpa_s->after_wps = 5; 431*f05cddf9SRui Paulo wpa_s->wps_freq = wpa_s->assoc_freq; 432*f05cddf9SRui Paulo 43339beb93cSSam Leffler return 0; 43439beb93cSSam Leffler } 43539beb93cSSam Leffler 43639beb93cSSam Leffler 437*f05cddf9SRui Paulo #ifdef CONFIG_P2P 438*f05cddf9SRui Paulo static void wpas_wps_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx) 439*f05cddf9SRui Paulo { 440*f05cddf9SRui Paulo struct wpa_supplicant *wpa_s = eloop_ctx; 441*f05cddf9SRui Paulo wpas_p2p_notif_pbc_overlap(wpa_s); 442*f05cddf9SRui Paulo } 443*f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 444*f05cddf9SRui Paulo 445*f05cddf9SRui Paulo 44639beb93cSSam Leffler static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s, 44739beb93cSSam Leffler struct wps_event_m2d *m2d) 44839beb93cSSam Leffler { 44939beb93cSSam Leffler wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_M2D 45039beb93cSSam Leffler "dev_password_id=%d config_error=%d", 45139beb93cSSam Leffler m2d->dev_password_id, m2d->config_error); 452e28a4053SRui Paulo wpas_notify_wps_event_m2d(wpa_s, m2d); 453*f05cddf9SRui Paulo #ifdef CONFIG_P2P 454*f05cddf9SRui Paulo if (wpa_s->parent && wpa_s->parent != wpa_s) { 455*f05cddf9SRui Paulo wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_M2D 456*f05cddf9SRui Paulo "dev_password_id=%d config_error=%d", 457*f05cddf9SRui Paulo m2d->dev_password_id, m2d->config_error); 458*f05cddf9SRui Paulo } 459*f05cddf9SRui Paulo if (m2d->config_error == WPS_CFG_MULTIPLE_PBC_DETECTED) { 460*f05cddf9SRui Paulo /* 461*f05cddf9SRui Paulo * Notify P2P from eloop timeout to avoid issues with the 462*f05cddf9SRui Paulo * interface getting removed while processing a message. 463*f05cddf9SRui Paulo */ 464*f05cddf9SRui Paulo eloop_register_timeout(0, 0, wpas_wps_pbc_overlap_cb, wpa_s, 465*f05cddf9SRui Paulo NULL); 466*f05cddf9SRui Paulo } 467*f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 46839beb93cSSam Leffler } 46939beb93cSSam Leffler 47039beb93cSSam Leffler 471*f05cddf9SRui Paulo static const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = { 472*f05cddf9SRui Paulo "No Error", /* WPS_EI_NO_ERROR */ 473*f05cddf9SRui Paulo "TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */ 474*f05cddf9SRui Paulo "WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */ 475*f05cddf9SRui Paulo }; 476*f05cddf9SRui Paulo 47739beb93cSSam Leffler static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s, 47839beb93cSSam Leffler struct wps_event_fail *fail) 47939beb93cSSam Leffler { 480*f05cddf9SRui Paulo if (fail->error_indication > 0 && 481*f05cddf9SRui Paulo fail->error_indication < NUM_WPS_EI_VALUES) { 482*f05cddf9SRui Paulo wpa_msg(wpa_s, MSG_INFO, 483*f05cddf9SRui Paulo WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)", 484*f05cddf9SRui Paulo fail->msg, fail->config_error, fail->error_indication, 485*f05cddf9SRui Paulo wps_event_fail_reason[fail->error_indication]); 486*f05cddf9SRui Paulo if (wpa_s->parent && wpa_s->parent != wpa_s) 487*f05cddf9SRui Paulo wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL 488*f05cddf9SRui Paulo "msg=%d config_error=%d reason=%d (%s)", 489*f05cddf9SRui Paulo fail->msg, fail->config_error, 490*f05cddf9SRui Paulo fail->error_indication, 491*f05cddf9SRui Paulo wps_event_fail_reason[fail->error_indication]); 492*f05cddf9SRui Paulo } else { 493*f05cddf9SRui Paulo wpa_msg(wpa_s, MSG_INFO, 494*f05cddf9SRui Paulo WPS_EVENT_FAIL "msg=%d config_error=%d", 495*f05cddf9SRui Paulo fail->msg, fail->config_error); 496*f05cddf9SRui Paulo if (wpa_s->parent && wpa_s->parent != wpa_s) 497*f05cddf9SRui Paulo wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL 498*f05cddf9SRui Paulo "msg=%d config_error=%d", 499*f05cddf9SRui Paulo fail->msg, fail->config_error); 500*f05cddf9SRui Paulo } 50139beb93cSSam Leffler wpas_clear_wps(wpa_s); 502e28a4053SRui Paulo wpas_notify_wps_event_fail(wpa_s, fail); 503*f05cddf9SRui Paulo #ifdef CONFIG_P2P 504*f05cddf9SRui Paulo wpas_p2p_wps_failed(wpa_s, fail); 505*f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 506*f05cddf9SRui Paulo } 507*f05cddf9SRui Paulo 508*f05cddf9SRui Paulo 509*f05cddf9SRui Paulo static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx); 510*f05cddf9SRui Paulo 511*f05cddf9SRui Paulo static void wpas_wps_reenable_networks(struct wpa_supplicant *wpa_s) 512*f05cddf9SRui Paulo { 513*f05cddf9SRui Paulo struct wpa_ssid *ssid; 514*f05cddf9SRui Paulo int changed = 0; 515*f05cddf9SRui Paulo 516*f05cddf9SRui Paulo eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL); 517*f05cddf9SRui Paulo 518*f05cddf9SRui Paulo for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { 519*f05cddf9SRui Paulo if (ssid->disabled_for_connect && ssid->disabled) { 520*f05cddf9SRui Paulo ssid->disabled_for_connect = 0; 521*f05cddf9SRui Paulo ssid->disabled = 0; 522*f05cddf9SRui Paulo wpas_notify_network_enabled_changed(wpa_s, ssid); 523*f05cddf9SRui Paulo changed++; 524*f05cddf9SRui Paulo } 525*f05cddf9SRui Paulo } 526*f05cddf9SRui Paulo 527*f05cddf9SRui Paulo if (changed) { 528*f05cddf9SRui Paulo #ifndef CONFIG_NO_CONFIG_WRITE 529*f05cddf9SRui Paulo if (wpa_s->conf->update_config && 530*f05cddf9SRui Paulo wpa_config_write(wpa_s->confname, wpa_s->conf)) { 531*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Failed to update " 532*f05cddf9SRui Paulo "configuration"); 533*f05cddf9SRui Paulo } 534*f05cddf9SRui Paulo #endif /* CONFIG_NO_CONFIG_WRITE */ 535*f05cddf9SRui Paulo } 536*f05cddf9SRui Paulo } 537*f05cddf9SRui Paulo 538*f05cddf9SRui Paulo 539*f05cddf9SRui Paulo static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx) 540*f05cddf9SRui Paulo { 541*f05cddf9SRui Paulo struct wpa_supplicant *wpa_s = eloop_ctx; 542*f05cddf9SRui Paulo /* Enable the networks disabled during wpas_wps_reassoc */ 543*f05cddf9SRui Paulo wpas_wps_reenable_networks(wpa_s); 54439beb93cSSam Leffler } 54539beb93cSSam Leffler 54639beb93cSSam Leffler 54739beb93cSSam Leffler static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s) 54839beb93cSSam Leffler { 54939beb93cSSam Leffler wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS); 55039beb93cSSam Leffler wpa_s->wps_success = 1; 551e28a4053SRui Paulo wpas_notify_wps_event_success(wpa_s); 552*f05cddf9SRui Paulo 553*f05cddf9SRui Paulo /* 554*f05cddf9SRui Paulo * Enable the networks disabled during wpas_wps_reassoc after 10 555*f05cddf9SRui Paulo * seconds. The 10 seconds timer is to allow the data connection to be 556*f05cddf9SRui Paulo * formed before allowing other networks to be selected. 557*f05cddf9SRui Paulo */ 558*f05cddf9SRui Paulo eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s, 559*f05cddf9SRui Paulo NULL); 560*f05cddf9SRui Paulo 561*f05cddf9SRui Paulo #ifdef CONFIG_P2P 562*f05cddf9SRui Paulo wpas_p2p_wps_success(wpa_s, wpa_s->bssid, 0); 563*f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 564e28a4053SRui Paulo } 565e28a4053SRui Paulo 566e28a4053SRui Paulo 567e28a4053SRui Paulo static void wpa_supplicant_wps_event_er_ap_add(struct wpa_supplicant *wpa_s, 568e28a4053SRui Paulo struct wps_event_er_ap *ap) 569e28a4053SRui Paulo { 570e28a4053SRui Paulo char uuid_str[100]; 571e28a4053SRui Paulo char dev_type[WPS_DEV_TYPE_BUFSIZE]; 572e28a4053SRui Paulo 573e28a4053SRui Paulo uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str)); 574e28a4053SRui Paulo if (ap->pri_dev_type) 575e28a4053SRui Paulo wps_dev_type_bin2str(ap->pri_dev_type, dev_type, 576e28a4053SRui Paulo sizeof(dev_type)); 577e28a4053SRui Paulo else 578e28a4053SRui Paulo dev_type[0] = '\0'; 579e28a4053SRui Paulo 580e28a4053SRui Paulo wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_ADD "%s " MACSTR 581e28a4053SRui Paulo " pri_dev_type=%s wps_state=%d |%s|%s|%s|%s|%s|%s|", 582e28a4053SRui Paulo uuid_str, MAC2STR(ap->mac_addr), dev_type, ap->wps_state, 583e28a4053SRui Paulo ap->friendly_name ? ap->friendly_name : "", 584e28a4053SRui Paulo ap->manufacturer ? ap->manufacturer : "", 585e28a4053SRui Paulo ap->model_description ? ap->model_description : "", 586e28a4053SRui Paulo ap->model_name ? ap->model_name : "", 587e28a4053SRui Paulo ap->manufacturer_url ? ap->manufacturer_url : "", 588e28a4053SRui Paulo ap->model_url ? ap->model_url : ""); 589e28a4053SRui Paulo } 590e28a4053SRui Paulo 591e28a4053SRui Paulo 592e28a4053SRui Paulo static void wpa_supplicant_wps_event_er_ap_remove(struct wpa_supplicant *wpa_s, 593e28a4053SRui Paulo struct wps_event_er_ap *ap) 594e28a4053SRui Paulo { 595e28a4053SRui Paulo char uuid_str[100]; 596e28a4053SRui Paulo uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str)); 597e28a4053SRui Paulo wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_REMOVE "%s", uuid_str); 598e28a4053SRui Paulo } 599e28a4053SRui Paulo 600e28a4053SRui Paulo 601e28a4053SRui Paulo static void wpa_supplicant_wps_event_er_enrollee_add( 602e28a4053SRui Paulo struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee) 603e28a4053SRui Paulo { 604e28a4053SRui Paulo char uuid_str[100]; 605e28a4053SRui Paulo char dev_type[WPS_DEV_TYPE_BUFSIZE]; 606e28a4053SRui Paulo 607e28a4053SRui Paulo uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str)); 608e28a4053SRui Paulo if (enrollee->pri_dev_type) 609e28a4053SRui Paulo wps_dev_type_bin2str(enrollee->pri_dev_type, dev_type, 610e28a4053SRui Paulo sizeof(dev_type)); 611e28a4053SRui Paulo else 612e28a4053SRui Paulo dev_type[0] = '\0'; 613e28a4053SRui Paulo 614e28a4053SRui Paulo wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_ADD "%s " MACSTR 615e28a4053SRui Paulo " M1=%d config_methods=0x%x dev_passwd_id=%d pri_dev_type=%s " 616e28a4053SRui Paulo "|%s|%s|%s|%s|%s|", 617e28a4053SRui Paulo uuid_str, MAC2STR(enrollee->mac_addr), enrollee->m1_received, 618e28a4053SRui Paulo enrollee->config_methods, enrollee->dev_passwd_id, dev_type, 619e28a4053SRui Paulo enrollee->dev_name ? enrollee->dev_name : "", 620e28a4053SRui Paulo enrollee->manufacturer ? enrollee->manufacturer : "", 621e28a4053SRui Paulo enrollee->model_name ? enrollee->model_name : "", 622e28a4053SRui Paulo enrollee->model_number ? enrollee->model_number : "", 623e28a4053SRui Paulo enrollee->serial_number ? enrollee->serial_number : ""); 624e28a4053SRui Paulo } 625e28a4053SRui Paulo 626e28a4053SRui Paulo 627e28a4053SRui Paulo static void wpa_supplicant_wps_event_er_enrollee_remove( 628e28a4053SRui Paulo struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee) 629e28a4053SRui Paulo { 630e28a4053SRui Paulo char uuid_str[100]; 631e28a4053SRui Paulo uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str)); 632e28a4053SRui Paulo wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_REMOVE "%s " MACSTR, 633e28a4053SRui Paulo uuid_str, MAC2STR(enrollee->mac_addr)); 63439beb93cSSam Leffler } 63539beb93cSSam Leffler 63639beb93cSSam Leffler 637*f05cddf9SRui Paulo static void wpa_supplicant_wps_event_er_ap_settings( 638*f05cddf9SRui Paulo struct wpa_supplicant *wpa_s, 639*f05cddf9SRui Paulo struct wps_event_er_ap_settings *ap_settings) 640*f05cddf9SRui Paulo { 641*f05cddf9SRui Paulo char uuid_str[100]; 642*f05cddf9SRui Paulo char key_str[65]; 643*f05cddf9SRui Paulo const struct wps_credential *cred = ap_settings->cred; 644*f05cddf9SRui Paulo 645*f05cddf9SRui Paulo key_str[0] = '\0'; 646*f05cddf9SRui Paulo if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) { 647*f05cddf9SRui Paulo if (cred->key_len >= 8 && cred->key_len <= 64) { 648*f05cddf9SRui Paulo os_memcpy(key_str, cred->key, cred->key_len); 649*f05cddf9SRui Paulo key_str[cred->key_len] = '\0'; 650*f05cddf9SRui Paulo } 651*f05cddf9SRui Paulo } 652*f05cddf9SRui Paulo 653*f05cddf9SRui Paulo uuid_bin2str(ap_settings->uuid, uuid_str, sizeof(uuid_str)); 654*f05cddf9SRui Paulo /* Use wpa_msg_ctrl to avoid showing the key in debug log */ 655*f05cddf9SRui Paulo wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_SETTINGS 656*f05cddf9SRui Paulo "uuid=%s ssid=%s auth_type=0x%04x encr_type=0x%04x " 657*f05cddf9SRui Paulo "key=%s", 658*f05cddf9SRui Paulo uuid_str, wpa_ssid_txt(cred->ssid, cred->ssid_len), 659*f05cddf9SRui Paulo cred->auth_type, cred->encr_type, key_str); 660*f05cddf9SRui Paulo } 661*f05cddf9SRui Paulo 662*f05cddf9SRui Paulo 663*f05cddf9SRui Paulo static void wpa_supplicant_wps_event_er_set_sel_reg( 664*f05cddf9SRui Paulo struct wpa_supplicant *wpa_s, 665*f05cddf9SRui Paulo struct wps_event_er_set_selected_registrar *ev) 666*f05cddf9SRui Paulo { 667*f05cddf9SRui Paulo char uuid_str[100]; 668*f05cddf9SRui Paulo 669*f05cddf9SRui Paulo uuid_bin2str(ev->uuid, uuid_str, sizeof(uuid_str)); 670*f05cddf9SRui Paulo switch (ev->state) { 671*f05cddf9SRui Paulo case WPS_ER_SET_SEL_REG_START: 672*f05cddf9SRui Paulo wpa_msg(wpa_s, MSG_DEBUG, WPS_EVENT_ER_SET_SEL_REG 673*f05cddf9SRui Paulo "uuid=%s state=START sel_reg=%d dev_passwd_id=%u " 674*f05cddf9SRui Paulo "sel_reg_config_methods=0x%x", 675*f05cddf9SRui Paulo uuid_str, ev->sel_reg, ev->dev_passwd_id, 676*f05cddf9SRui Paulo ev->sel_reg_config_methods); 677*f05cddf9SRui Paulo break; 678*f05cddf9SRui Paulo case WPS_ER_SET_SEL_REG_DONE: 679*f05cddf9SRui Paulo wpa_msg(wpa_s, MSG_DEBUG, WPS_EVENT_ER_SET_SEL_REG 680*f05cddf9SRui Paulo "uuid=%s state=DONE", uuid_str); 681*f05cddf9SRui Paulo break; 682*f05cddf9SRui Paulo case WPS_ER_SET_SEL_REG_FAILED: 683*f05cddf9SRui Paulo wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_SET_SEL_REG 684*f05cddf9SRui Paulo "uuid=%s state=FAILED", uuid_str); 685*f05cddf9SRui Paulo break; 686*f05cddf9SRui Paulo } 687*f05cddf9SRui Paulo } 688*f05cddf9SRui Paulo 689*f05cddf9SRui Paulo 69039beb93cSSam Leffler static void wpa_supplicant_wps_event(void *ctx, enum wps_event event, 69139beb93cSSam Leffler union wps_event_data *data) 69239beb93cSSam Leffler { 69339beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 69439beb93cSSam Leffler switch (event) { 69539beb93cSSam Leffler case WPS_EV_M2D: 69639beb93cSSam Leffler wpa_supplicant_wps_event_m2d(wpa_s, &data->m2d); 69739beb93cSSam Leffler break; 69839beb93cSSam Leffler case WPS_EV_FAIL: 69939beb93cSSam Leffler wpa_supplicant_wps_event_fail(wpa_s, &data->fail); 70039beb93cSSam Leffler break; 70139beb93cSSam Leffler case WPS_EV_SUCCESS: 70239beb93cSSam Leffler wpa_supplicant_wps_event_success(wpa_s); 70339beb93cSSam Leffler break; 70439beb93cSSam Leffler case WPS_EV_PWD_AUTH_FAIL: 705*f05cddf9SRui Paulo #ifdef CONFIG_AP 706*f05cddf9SRui Paulo if (wpa_s->ap_iface && data->pwd_auth_fail.enrollee) 707*f05cddf9SRui Paulo wpa_supplicant_ap_pwd_auth_fail(wpa_s); 708*f05cddf9SRui Paulo #endif /* CONFIG_AP */ 70939beb93cSSam Leffler break; 7103157ba21SRui Paulo case WPS_EV_PBC_OVERLAP: 7113157ba21SRui Paulo break; 7123157ba21SRui Paulo case WPS_EV_PBC_TIMEOUT: 7133157ba21SRui Paulo break; 714e28a4053SRui Paulo case WPS_EV_ER_AP_ADD: 715e28a4053SRui Paulo wpa_supplicant_wps_event_er_ap_add(wpa_s, &data->ap); 716e28a4053SRui Paulo break; 717e28a4053SRui Paulo case WPS_EV_ER_AP_REMOVE: 718e28a4053SRui Paulo wpa_supplicant_wps_event_er_ap_remove(wpa_s, &data->ap); 719e28a4053SRui Paulo break; 720e28a4053SRui Paulo case WPS_EV_ER_ENROLLEE_ADD: 721e28a4053SRui Paulo wpa_supplicant_wps_event_er_enrollee_add(wpa_s, 722e28a4053SRui Paulo &data->enrollee); 723e28a4053SRui Paulo break; 724e28a4053SRui Paulo case WPS_EV_ER_ENROLLEE_REMOVE: 725e28a4053SRui Paulo wpa_supplicant_wps_event_er_enrollee_remove(wpa_s, 726e28a4053SRui Paulo &data->enrollee); 727e28a4053SRui Paulo break; 728*f05cddf9SRui Paulo case WPS_EV_ER_AP_SETTINGS: 729*f05cddf9SRui Paulo wpa_supplicant_wps_event_er_ap_settings(wpa_s, 730*f05cddf9SRui Paulo &data->ap_settings); 731*f05cddf9SRui Paulo break; 732*f05cddf9SRui Paulo case WPS_EV_ER_SET_SELECTED_REGISTRAR: 733*f05cddf9SRui Paulo wpa_supplicant_wps_event_er_set_sel_reg(wpa_s, 734*f05cddf9SRui Paulo &data->set_sel_reg); 735*f05cddf9SRui Paulo break; 736*f05cddf9SRui Paulo case WPS_EV_AP_PIN_SUCCESS: 737*f05cddf9SRui Paulo break; 73839beb93cSSam Leffler } 73939beb93cSSam Leffler } 74039beb93cSSam Leffler 74139beb93cSSam Leffler 74239beb93cSSam Leffler enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid) 74339beb93cSSam Leffler { 74439beb93cSSam Leffler if (eap_is_wps_pbc_enrollee(&ssid->eap) || 74539beb93cSSam Leffler eap_is_wps_pin_enrollee(&ssid->eap)) 74639beb93cSSam Leffler return WPS_REQ_ENROLLEE; 74739beb93cSSam Leffler else 74839beb93cSSam Leffler return WPS_REQ_REGISTRAR; 74939beb93cSSam Leffler } 75039beb93cSSam Leffler 75139beb93cSSam Leffler 75239beb93cSSam Leffler static void wpas_clear_wps(struct wpa_supplicant *wpa_s) 75339beb93cSSam Leffler { 75439beb93cSSam Leffler int id; 755*f05cddf9SRui Paulo struct wpa_ssid *ssid, *remove_ssid = NULL, *prev_current; 756*f05cddf9SRui Paulo 757*f05cddf9SRui Paulo prev_current = wpa_s->current_ssid; 758*f05cddf9SRui Paulo 759*f05cddf9SRui Paulo /* Enable the networks disabled during wpas_wps_reassoc */ 760*f05cddf9SRui Paulo wpas_wps_reenable_networks(wpa_s); 76139beb93cSSam Leffler 76239beb93cSSam Leffler eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL); 76339beb93cSSam Leffler 76439beb93cSSam Leffler /* Remove any existing WPS network from configuration */ 76539beb93cSSam Leffler ssid = wpa_s->conf->ssid; 76639beb93cSSam Leffler while (ssid) { 76739beb93cSSam Leffler if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) { 768e28a4053SRui Paulo if (ssid == wpa_s->current_ssid) { 76939beb93cSSam Leffler wpa_s->current_ssid = NULL; 770e28a4053SRui Paulo if (ssid != NULL) 771e28a4053SRui Paulo wpas_notify_network_changed(wpa_s); 772e28a4053SRui Paulo } 77339beb93cSSam Leffler id = ssid->id; 774e28a4053SRui Paulo remove_ssid = ssid; 77539beb93cSSam Leffler } else 77639beb93cSSam Leffler id = -1; 77739beb93cSSam Leffler ssid = ssid->next; 778e28a4053SRui Paulo if (id >= 0) { 779*f05cddf9SRui Paulo if (prev_current == remove_ssid) { 780*f05cddf9SRui Paulo wpa_sm_set_config(wpa_s->wpa, NULL); 781*f05cddf9SRui Paulo eapol_sm_notify_config(wpa_s->eapol, NULL, 782*f05cddf9SRui Paulo NULL); 783*f05cddf9SRui Paulo } 784e28a4053SRui Paulo wpas_notify_network_removed(wpa_s, remove_ssid); 78539beb93cSSam Leffler wpa_config_remove_network(wpa_s->conf, id); 78639beb93cSSam Leffler } 78739beb93cSSam Leffler } 788*f05cddf9SRui Paulo 789*f05cddf9SRui Paulo wpas_wps_clear_ap_info(wpa_s); 790e28a4053SRui Paulo } 79139beb93cSSam Leffler 79239beb93cSSam Leffler 79339beb93cSSam Leffler static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx) 79439beb93cSSam Leffler { 79539beb93cSSam Leffler struct wpa_supplicant *wpa_s = eloop_ctx; 796*f05cddf9SRui Paulo wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed " 79739beb93cSSam Leffler "out"); 79839beb93cSSam Leffler wpas_clear_wps(wpa_s); 79939beb93cSSam Leffler } 80039beb93cSSam Leffler 80139beb93cSSam Leffler 80239beb93cSSam Leffler static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s, 80339beb93cSSam Leffler int registrar, const u8 *bssid) 80439beb93cSSam Leffler { 80539beb93cSSam Leffler struct wpa_ssid *ssid; 80639beb93cSSam Leffler 80739beb93cSSam Leffler ssid = wpa_config_add_network(wpa_s->conf); 80839beb93cSSam Leffler if (ssid == NULL) 80939beb93cSSam Leffler return NULL; 810e28a4053SRui Paulo wpas_notify_network_added(wpa_s, ssid); 81139beb93cSSam Leffler wpa_config_set_network_defaults(ssid); 812*f05cddf9SRui Paulo ssid->temporary = 1; 81339beb93cSSam Leffler if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 || 81439beb93cSSam Leffler wpa_config_set(ssid, "eap", "WSC", 0) < 0 || 81539beb93cSSam Leffler wpa_config_set(ssid, "identity", registrar ? 81639beb93cSSam Leffler "\"" WSC_ID_REGISTRAR "\"" : 81739beb93cSSam Leffler "\"" WSC_ID_ENROLLEE "\"", 0) < 0) { 818e28a4053SRui Paulo wpas_notify_network_removed(wpa_s, ssid); 81939beb93cSSam Leffler wpa_config_remove_network(wpa_s->conf, ssid->id); 82039beb93cSSam Leffler return NULL; 82139beb93cSSam Leffler } 82239beb93cSSam Leffler 82339beb93cSSam Leffler if (bssid) { 824*f05cddf9SRui Paulo #ifndef CONFIG_P2P 825e28a4053SRui Paulo struct wpa_bss *bss; 8263157ba21SRui Paulo int count = 0; 827*f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 82839beb93cSSam Leffler 82939beb93cSSam Leffler os_memcpy(ssid->bssid, bssid, ETH_ALEN); 83039beb93cSSam Leffler ssid->bssid_set = 1; 83139beb93cSSam Leffler 832*f05cddf9SRui Paulo /* 833*f05cddf9SRui Paulo * Note: With P2P, the SSID may change at the time the WPS 834*f05cddf9SRui Paulo * provisioning is started, so better not filter the AP based 835*f05cddf9SRui Paulo * on the current SSID in the scan results. 836*f05cddf9SRui Paulo */ 837*f05cddf9SRui Paulo #ifndef CONFIG_P2P 838e28a4053SRui Paulo dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 839e28a4053SRui Paulo if (os_memcmp(bssid, bss->bssid, ETH_ALEN) != 0) 84039beb93cSSam Leffler continue; 84139beb93cSSam Leffler 84239beb93cSSam Leffler os_free(ssid->ssid); 843e28a4053SRui Paulo ssid->ssid = os_malloc(bss->ssid_len); 84439beb93cSSam Leffler if (ssid->ssid == NULL) 84539beb93cSSam Leffler break; 846e28a4053SRui Paulo os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len); 847e28a4053SRui Paulo ssid->ssid_len = bss->ssid_len; 8483157ba21SRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "WPS: Picked SSID from " 8493157ba21SRui Paulo "scan results", 8503157ba21SRui Paulo ssid->ssid, ssid->ssid_len); 8513157ba21SRui Paulo count++; 8523157ba21SRui Paulo } 8533157ba21SRui Paulo 8543157ba21SRui Paulo if (count > 1) { 8553157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: More than one SSID found " 8563157ba21SRui Paulo "for the AP; use wildcard"); 8573157ba21SRui Paulo os_free(ssid->ssid); 8583157ba21SRui Paulo ssid->ssid = NULL; 8593157ba21SRui Paulo ssid->ssid_len = 0; 86039beb93cSSam Leffler } 861*f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 86239beb93cSSam Leffler } 86339beb93cSSam Leffler 86439beb93cSSam Leffler return ssid; 86539beb93cSSam Leffler } 86639beb93cSSam Leffler 86739beb93cSSam Leffler 86839beb93cSSam Leffler static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s, 869*f05cddf9SRui Paulo struct wpa_ssid *selected, const u8 *bssid) 87039beb93cSSam Leffler { 87139beb93cSSam Leffler struct wpa_ssid *ssid; 872*f05cddf9SRui Paulo struct wpa_bss *bss; 873*f05cddf9SRui Paulo 874*f05cddf9SRui Paulo wpa_s->known_wps_freq = 0; 875*f05cddf9SRui Paulo if (bssid) { 876*f05cddf9SRui Paulo bss = wpa_bss_get_bssid(wpa_s, bssid); 877*f05cddf9SRui Paulo if (bss && bss->freq > 0) { 878*f05cddf9SRui Paulo wpa_s->known_wps_freq = 1; 879*f05cddf9SRui Paulo wpa_s->wps_freq = bss->freq; 880*f05cddf9SRui Paulo } 881*f05cddf9SRui Paulo } 882*f05cddf9SRui Paulo 883*f05cddf9SRui Paulo if (wpa_s->current_ssid) 884*f05cddf9SRui Paulo wpa_supplicant_deauthenticate( 885*f05cddf9SRui Paulo wpa_s, WLAN_REASON_DEAUTH_LEAVING); 88639beb93cSSam Leffler 88739beb93cSSam Leffler /* Mark all other networks disabled and trigger reassociation */ 88839beb93cSSam Leffler ssid = wpa_s->conf->ssid; 88939beb93cSSam Leffler while (ssid) { 890e28a4053SRui Paulo int was_disabled = ssid->disabled; 891*f05cddf9SRui Paulo ssid->disabled_for_connect = 0; 892*f05cddf9SRui Paulo /* 893*f05cddf9SRui Paulo * In case the network object corresponds to a persistent group 894*f05cddf9SRui Paulo * then do not send out network disabled signal. In addition, 895*f05cddf9SRui Paulo * do not change disabled status of persistent network objects 896*f05cddf9SRui Paulo * from 2 to 1 should we connect to another network. 897*f05cddf9SRui Paulo */ 898*f05cddf9SRui Paulo if (was_disabled != 2) { 89939beb93cSSam Leffler ssid->disabled = ssid != selected; 900*f05cddf9SRui Paulo if (was_disabled != ssid->disabled) { 901*f05cddf9SRui Paulo if (ssid->disabled) 902*f05cddf9SRui Paulo ssid->disabled_for_connect = 1; 903*f05cddf9SRui Paulo wpas_notify_network_enabled_changed(wpa_s, 904*f05cddf9SRui Paulo ssid); 905*f05cddf9SRui Paulo } 906*f05cddf9SRui Paulo } 90739beb93cSSam Leffler ssid = ssid->next; 90839beb93cSSam Leffler } 90939beb93cSSam Leffler wpa_s->disconnected = 0; 91039beb93cSSam Leffler wpa_s->reassociate = 1; 91139beb93cSSam Leffler wpa_s->scan_runs = 0; 912*f05cddf9SRui Paulo wpa_s->normal_scans = 0; 91339beb93cSSam Leffler wpa_s->wps_success = 0; 91439beb93cSSam Leffler wpa_s->blacklist_cleared = 0; 91539beb93cSSam Leffler wpa_supplicant_req_scan(wpa_s, 0, 0); 91639beb93cSSam Leffler } 91739beb93cSSam Leffler 91839beb93cSSam Leffler 919*f05cddf9SRui Paulo int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, 920*f05cddf9SRui Paulo int p2p_group) 92139beb93cSSam Leffler { 92239beb93cSSam Leffler struct wpa_ssid *ssid; 92339beb93cSSam Leffler wpas_clear_wps(wpa_s); 92439beb93cSSam Leffler ssid = wpas_wps_add_network(wpa_s, 0, bssid); 92539beb93cSSam Leffler if (ssid == NULL) 92639beb93cSSam Leffler return -1; 927*f05cddf9SRui Paulo ssid->temporary = 1; 928*f05cddf9SRui Paulo ssid->p2p_group = p2p_group; 929*f05cddf9SRui Paulo #ifdef CONFIG_P2P 930*f05cddf9SRui Paulo if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) { 931*f05cddf9SRui Paulo ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1); 932*f05cddf9SRui Paulo if (ssid->ssid) { 933*f05cddf9SRui Paulo ssid->ssid_len = wpa_s->go_params->ssid_len; 934*f05cddf9SRui Paulo os_memcpy(ssid->ssid, wpa_s->go_params->ssid, 935*f05cddf9SRui Paulo ssid->ssid_len); 936*f05cddf9SRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP " 937*f05cddf9SRui Paulo "SSID", ssid->ssid, ssid->ssid_len); 938*f05cddf9SRui Paulo } 939*f05cddf9SRui Paulo } 940*f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 94139beb93cSSam Leffler wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0); 942*f05cddf9SRui Paulo if (wpa_s->wps_fragment_size) 943*f05cddf9SRui Paulo ssid->eap.fragment_size = wpa_s->wps_fragment_size; 94439beb93cSSam Leffler eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, 94539beb93cSSam Leffler wpa_s, NULL); 946*f05cddf9SRui Paulo wpas_wps_reassoc(wpa_s, ssid, bssid); 94739beb93cSSam Leffler return 0; 94839beb93cSSam Leffler } 94939beb93cSSam Leffler 95039beb93cSSam Leffler 95139beb93cSSam Leffler int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, 952*f05cddf9SRui Paulo const char *pin, int p2p_group, u16 dev_pw_id) 95339beb93cSSam Leffler { 95439beb93cSSam Leffler struct wpa_ssid *ssid; 955e28a4053SRui Paulo char val[128]; 95639beb93cSSam Leffler unsigned int rpin = 0; 95739beb93cSSam Leffler 95839beb93cSSam Leffler wpas_clear_wps(wpa_s); 95939beb93cSSam Leffler ssid = wpas_wps_add_network(wpa_s, 0, bssid); 96039beb93cSSam Leffler if (ssid == NULL) 96139beb93cSSam Leffler return -1; 962*f05cddf9SRui Paulo ssid->temporary = 1; 963*f05cddf9SRui Paulo ssid->p2p_group = p2p_group; 964*f05cddf9SRui Paulo #ifdef CONFIG_P2P 965*f05cddf9SRui Paulo if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) { 966*f05cddf9SRui Paulo ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1); 967*f05cddf9SRui Paulo if (ssid->ssid) { 968*f05cddf9SRui Paulo ssid->ssid_len = wpa_s->go_params->ssid_len; 969*f05cddf9SRui Paulo os_memcpy(ssid->ssid, wpa_s->go_params->ssid, 970*f05cddf9SRui Paulo ssid->ssid_len); 971*f05cddf9SRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP " 972*f05cddf9SRui Paulo "SSID", ssid->ssid, ssid->ssid_len); 973*f05cddf9SRui Paulo } 974*f05cddf9SRui Paulo } 975*f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 97639beb93cSSam Leffler if (pin) 977*f05cddf9SRui Paulo os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u\"", 978*f05cddf9SRui Paulo pin, dev_pw_id); 97939beb93cSSam Leffler else { 98039beb93cSSam Leffler rpin = wps_generate_pin(); 981*f05cddf9SRui Paulo os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u\"", 982*f05cddf9SRui Paulo rpin, dev_pw_id); 98339beb93cSSam Leffler } 98439beb93cSSam Leffler wpa_config_set(ssid, "phase1", val, 0); 985*f05cddf9SRui Paulo if (wpa_s->wps_fragment_size) 986*f05cddf9SRui Paulo ssid->eap.fragment_size = wpa_s->wps_fragment_size; 98739beb93cSSam Leffler eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, 98839beb93cSSam Leffler wpa_s, NULL); 989*f05cddf9SRui Paulo wpa_s->wps_ap_iter = 1; 990*f05cddf9SRui Paulo wpas_wps_reassoc(wpa_s, ssid, bssid); 99139beb93cSSam Leffler return rpin; 99239beb93cSSam Leffler } 99339beb93cSSam Leffler 99439beb93cSSam Leffler 995*f05cddf9SRui Paulo /* Cancel the wps pbc/pin requests */ 996*f05cddf9SRui Paulo int wpas_wps_cancel(struct wpa_supplicant *wpa_s) 997e28a4053SRui Paulo { 998*f05cddf9SRui Paulo #ifdef CONFIG_AP 999*f05cddf9SRui Paulo if (wpa_s->ap_iface) { 1000*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Cancelling in AP mode"); 1001*f05cddf9SRui Paulo return wpa_supplicant_ap_wps_cancel(wpa_s); 1002e28a4053SRui Paulo } 1003*f05cddf9SRui Paulo #endif /* CONFIG_AP */ 1004e28a4053SRui Paulo 1005*f05cddf9SRui Paulo if (wpa_s->wpa_state == WPA_SCANNING || 1006*f05cddf9SRui Paulo wpa_s->wpa_state == WPA_DISCONNECTED) { 1007*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Cancel operation - cancel scan"); 1008*f05cddf9SRui Paulo wpa_supplicant_cancel_scan(wpa_s); 1009e28a4053SRui Paulo wpas_clear_wps(wpa_s); 1010*f05cddf9SRui Paulo } else if (wpa_s->wpa_state >= WPA_ASSOCIATED) { 1011*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Cancel operation - " 1012*f05cddf9SRui Paulo "deauthenticate"); 1013*f05cddf9SRui Paulo wpa_supplicant_deauthenticate(wpa_s, 1014*f05cddf9SRui Paulo WLAN_REASON_DEAUTH_LEAVING); 1015*f05cddf9SRui Paulo wpas_clear_wps(wpa_s); 1016*f05cddf9SRui Paulo } else { 1017*f05cddf9SRui Paulo wpas_wps_reenable_networks(wpa_s); 1018*f05cddf9SRui Paulo wpas_wps_clear_ap_info(wpa_s); 1019*f05cddf9SRui Paulo } 1020e28a4053SRui Paulo 1021e28a4053SRui Paulo return 0; 1022e28a4053SRui Paulo } 1023e28a4053SRui Paulo 1024e28a4053SRui Paulo 102539beb93cSSam Leffler int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid, 1026e28a4053SRui Paulo const char *pin, struct wps_new_ap_settings *settings) 102739beb93cSSam Leffler { 102839beb93cSSam Leffler struct wpa_ssid *ssid; 1029e28a4053SRui Paulo char val[200]; 1030e28a4053SRui Paulo char *pos, *end; 1031e28a4053SRui Paulo int res; 103239beb93cSSam Leffler 103339beb93cSSam Leffler if (!pin) 103439beb93cSSam Leffler return -1; 103539beb93cSSam Leffler wpas_clear_wps(wpa_s); 103639beb93cSSam Leffler ssid = wpas_wps_add_network(wpa_s, 1, bssid); 103739beb93cSSam Leffler if (ssid == NULL) 103839beb93cSSam Leffler return -1; 1039*f05cddf9SRui Paulo ssid->temporary = 1; 1040e28a4053SRui Paulo pos = val; 1041e28a4053SRui Paulo end = pos + sizeof(val); 1042e28a4053SRui Paulo res = os_snprintf(pos, end - pos, "\"pin=%s", pin); 1043e28a4053SRui Paulo if (res < 0 || res >= end - pos) 1044e28a4053SRui Paulo return -1; 1045e28a4053SRui Paulo pos += res; 1046e28a4053SRui Paulo if (settings) { 1047e28a4053SRui Paulo res = os_snprintf(pos, end - pos, " new_ssid=%s new_auth=%s " 1048e28a4053SRui Paulo "new_encr=%s new_key=%s", 1049e28a4053SRui Paulo settings->ssid_hex, settings->auth, 1050e28a4053SRui Paulo settings->encr, settings->key_hex); 1051e28a4053SRui Paulo if (res < 0 || res >= end - pos) 1052e28a4053SRui Paulo return -1; 1053e28a4053SRui Paulo pos += res; 1054e28a4053SRui Paulo } 1055e28a4053SRui Paulo res = os_snprintf(pos, end - pos, "\""); 1056e28a4053SRui Paulo if (res < 0 || res >= end - pos) 1057e28a4053SRui Paulo return -1; 105839beb93cSSam Leffler wpa_config_set(ssid, "phase1", val, 0); 1059*f05cddf9SRui Paulo if (wpa_s->wps_fragment_size) 1060*f05cddf9SRui Paulo ssid->eap.fragment_size = wpa_s->wps_fragment_size; 106139beb93cSSam Leffler eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, 106239beb93cSSam Leffler wpa_s, NULL); 1063*f05cddf9SRui Paulo wpas_wps_reassoc(wpa_s, ssid, bssid); 106439beb93cSSam Leffler return 0; 106539beb93cSSam Leffler } 106639beb93cSSam Leffler 106739beb93cSSam Leffler 106839beb93cSSam Leffler static int wpas_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk, 106939beb93cSSam Leffler size_t psk_len) 107039beb93cSSam Leffler { 107139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received new WPA/WPA2-PSK from WPS for " 107239beb93cSSam Leffler "STA " MACSTR, MAC2STR(mac_addr)); 107339beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len); 107439beb93cSSam Leffler 107539beb93cSSam Leffler /* TODO */ 107639beb93cSSam Leffler 107739beb93cSSam Leffler return 0; 107839beb93cSSam Leffler } 107939beb93cSSam Leffler 108039beb93cSSam Leffler 108139beb93cSSam Leffler static void wpas_wps_pin_needed_cb(void *ctx, const u8 *uuid_e, 108239beb93cSSam Leffler const struct wps_device_data *dev) 108339beb93cSSam Leffler { 108439beb93cSSam Leffler char uuid[40], txt[400]; 108539beb93cSSam Leffler int len; 1086e28a4053SRui Paulo char devtype[WPS_DEV_TYPE_BUFSIZE]; 108739beb93cSSam Leffler if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) 108839beb93cSSam Leffler return; 108939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: PIN needed for UUID-E %s", uuid); 109039beb93cSSam Leffler len = os_snprintf(txt, sizeof(txt), "WPS-EVENT-PIN-NEEDED %s " MACSTR 1091e28a4053SRui Paulo " [%s|%s|%s|%s|%s|%s]", 109239beb93cSSam Leffler uuid, MAC2STR(dev->mac_addr), dev->device_name, 109339beb93cSSam Leffler dev->manufacturer, dev->model_name, 109439beb93cSSam Leffler dev->model_number, dev->serial_number, 1095e28a4053SRui Paulo wps_dev_type_bin2str(dev->pri_dev_type, devtype, 1096e28a4053SRui Paulo sizeof(devtype))); 109739beb93cSSam Leffler if (len > 0 && len < (int) sizeof(txt)) 109839beb93cSSam Leffler wpa_printf(MSG_INFO, "%s", txt); 109939beb93cSSam Leffler } 110039beb93cSSam Leffler 110139beb93cSSam Leffler 1102e28a4053SRui Paulo static void wpas_wps_set_sel_reg_cb(void *ctx, int sel_reg, u16 dev_passwd_id, 1103e28a4053SRui Paulo u16 sel_reg_config_methods) 1104e28a4053SRui Paulo { 1105e28a4053SRui Paulo #ifdef CONFIG_WPS_ER 1106e28a4053SRui Paulo struct wpa_supplicant *wpa_s = ctx; 1107e28a4053SRui Paulo 1108e28a4053SRui Paulo if (wpa_s->wps_er == NULL) 1109e28a4053SRui Paulo return; 1110*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar - sel_reg=%d " 1111*f05cddf9SRui Paulo "dev_password_id=%u sel_reg_config_methods=0x%x", 1112*f05cddf9SRui Paulo sel_reg, dev_passwd_id, sel_reg_config_methods); 1113e28a4053SRui Paulo wps_er_set_sel_reg(wpa_s->wps_er, sel_reg, dev_passwd_id, 1114e28a4053SRui Paulo sel_reg_config_methods); 1115e28a4053SRui Paulo #endif /* CONFIG_WPS_ER */ 1116e28a4053SRui Paulo } 1117e28a4053SRui Paulo 1118e28a4053SRui Paulo 1119*f05cddf9SRui Paulo static u16 wps_fix_config_methods(u16 config_methods) 1120*f05cddf9SRui Paulo { 1121*f05cddf9SRui Paulo #ifdef CONFIG_WPS2 1122*f05cddf9SRui Paulo if ((config_methods & 1123*f05cddf9SRui Paulo (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY | 1124*f05cddf9SRui Paulo WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) { 1125*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Converting display to " 1126*f05cddf9SRui Paulo "virtual_display for WPS 2.0 compliance"); 1127*f05cddf9SRui Paulo config_methods |= WPS_CONFIG_VIRT_DISPLAY; 1128*f05cddf9SRui Paulo } 1129*f05cddf9SRui Paulo if ((config_methods & 1130*f05cddf9SRui Paulo (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON | 1131*f05cddf9SRui Paulo WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) { 1132*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Converting push_button to " 1133*f05cddf9SRui Paulo "virtual_push_button for WPS 2.0 compliance"); 1134*f05cddf9SRui Paulo config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON; 1135*f05cddf9SRui Paulo } 1136*f05cddf9SRui Paulo #endif /* CONFIG_WPS2 */ 1137*f05cddf9SRui Paulo 1138*f05cddf9SRui Paulo return config_methods; 1139*f05cddf9SRui Paulo } 1140*f05cddf9SRui Paulo 1141*f05cddf9SRui Paulo 1142*f05cddf9SRui Paulo static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s, 1143*f05cddf9SRui Paulo struct wps_context *wps) 1144*f05cddf9SRui Paulo { 1145*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Set UUID for interface %s", wpa_s->ifname); 1146*f05cddf9SRui Paulo if (is_nil_uuid(wpa_s->conf->uuid)) { 1147*f05cddf9SRui Paulo struct wpa_supplicant *first; 1148*f05cddf9SRui Paulo first = wpa_s->global->ifaces; 1149*f05cddf9SRui Paulo while (first && first->next) 1150*f05cddf9SRui Paulo first = first->next; 1151*f05cddf9SRui Paulo if (first && first != wpa_s) { 1152*f05cddf9SRui Paulo if (wps != wpa_s->global->ifaces->wps) 1153*f05cddf9SRui Paulo os_memcpy(wps->uuid, 1154*f05cddf9SRui Paulo wpa_s->global->ifaces->wps->uuid, 1155*f05cddf9SRui Paulo WPS_UUID_LEN); 1156*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: UUID from the first " 1157*f05cddf9SRui Paulo "interface", wps->uuid, WPS_UUID_LEN); 1158*f05cddf9SRui Paulo } else { 1159*f05cddf9SRui Paulo uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid); 1160*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC " 1161*f05cddf9SRui Paulo "address", wps->uuid, WPS_UUID_LEN); 1162*f05cddf9SRui Paulo } 1163*f05cddf9SRui Paulo } else { 1164*f05cddf9SRui Paulo os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN); 1165*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: UUID based on configuration", 1166*f05cddf9SRui Paulo wps->uuid, WPS_UUID_LEN); 1167*f05cddf9SRui Paulo } 1168*f05cddf9SRui Paulo } 1169*f05cddf9SRui Paulo 1170*f05cddf9SRui Paulo 1171*f05cddf9SRui Paulo static void wpas_wps_set_vendor_ext_m1(struct wpa_supplicant *wpa_s, 1172*f05cddf9SRui Paulo struct wps_context *wps) 1173*f05cddf9SRui Paulo { 1174*f05cddf9SRui Paulo wpabuf_free(wps->dev.vendor_ext_m1); 1175*f05cddf9SRui Paulo wps->dev.vendor_ext_m1 = NULL; 1176*f05cddf9SRui Paulo 1177*f05cddf9SRui Paulo if (wpa_s->conf->wps_vendor_ext_m1) { 1178*f05cddf9SRui Paulo wps->dev.vendor_ext_m1 = 1179*f05cddf9SRui Paulo wpabuf_dup(wpa_s->conf->wps_vendor_ext_m1); 1180*f05cddf9SRui Paulo if (!wps->dev.vendor_ext_m1) { 1181*f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "WPS: Cannot " 1182*f05cddf9SRui Paulo "allocate memory for vendor_ext_m1"); 1183*f05cddf9SRui Paulo } 1184*f05cddf9SRui Paulo } 1185*f05cddf9SRui Paulo } 1186*f05cddf9SRui Paulo 1187*f05cddf9SRui Paulo 118839beb93cSSam Leffler int wpas_wps_init(struct wpa_supplicant *wpa_s) 118939beb93cSSam Leffler { 119039beb93cSSam Leffler struct wps_context *wps; 119139beb93cSSam Leffler struct wps_registrar_config rcfg; 1192*f05cddf9SRui Paulo struct hostapd_hw_modes *modes; 1193*f05cddf9SRui Paulo u16 m; 119439beb93cSSam Leffler 119539beb93cSSam Leffler wps = os_zalloc(sizeof(*wps)); 119639beb93cSSam Leffler if (wps == NULL) 119739beb93cSSam Leffler return -1; 119839beb93cSSam Leffler 119939beb93cSSam Leffler wps->cred_cb = wpa_supplicant_wps_cred; 120039beb93cSSam Leffler wps->event_cb = wpa_supplicant_wps_event; 120139beb93cSSam Leffler wps->cb_ctx = wpa_s; 120239beb93cSSam Leffler 120339beb93cSSam Leffler wps->dev.device_name = wpa_s->conf->device_name; 120439beb93cSSam Leffler wps->dev.manufacturer = wpa_s->conf->manufacturer; 120539beb93cSSam Leffler wps->dev.model_name = wpa_s->conf->model_name; 120639beb93cSSam Leffler wps->dev.model_number = wpa_s->conf->model_number; 120739beb93cSSam Leffler wps->dev.serial_number = wpa_s->conf->serial_number; 1208e28a4053SRui Paulo wps->config_methods = 1209e28a4053SRui Paulo wps_config_methods_str2bin(wpa_s->conf->config_methods); 1210*f05cddf9SRui Paulo if ((wps->config_methods & (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) == 1211*f05cddf9SRui Paulo (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) { 1212*f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "WPS: Both Label and Display config " 1213*f05cddf9SRui Paulo "methods are not allowed at the same time"); 121439beb93cSSam Leffler os_free(wps); 121539beb93cSSam Leffler return -1; 121639beb93cSSam Leffler } 1217*f05cddf9SRui Paulo wps->config_methods = wps_fix_config_methods(wps->config_methods); 1218*f05cddf9SRui Paulo wps->dev.config_methods = wps->config_methods; 1219*f05cddf9SRui Paulo os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type, 1220*f05cddf9SRui Paulo WPS_DEV_TYPE_LEN); 1221*f05cddf9SRui Paulo 1222*f05cddf9SRui Paulo wps->dev.num_sec_dev_types = wpa_s->conf->num_sec_device_types; 1223*f05cddf9SRui Paulo os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type, 1224*f05cddf9SRui Paulo WPS_DEV_TYPE_LEN * wps->dev.num_sec_dev_types); 1225*f05cddf9SRui Paulo 1226*f05cddf9SRui Paulo wpas_wps_set_vendor_ext_m1(wpa_s, wps); 1227*f05cddf9SRui Paulo 122839beb93cSSam Leffler wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version); 1229*f05cddf9SRui Paulo modes = wpa_s->hw.modes; 1230*f05cddf9SRui Paulo if (modes) { 1231*f05cddf9SRui Paulo for (m = 0; m < wpa_s->hw.num_modes; m++) { 1232*f05cddf9SRui Paulo if (modes[m].mode == HOSTAPD_MODE_IEEE80211B || 1233*f05cddf9SRui Paulo modes[m].mode == HOSTAPD_MODE_IEEE80211G) 1234*f05cddf9SRui Paulo wps->dev.rf_bands |= WPS_RF_24GHZ; 1235*f05cddf9SRui Paulo else if (modes[m].mode == HOSTAPD_MODE_IEEE80211A) 1236*f05cddf9SRui Paulo wps->dev.rf_bands |= WPS_RF_50GHZ; 1237*f05cddf9SRui Paulo } 1238*f05cddf9SRui Paulo } 1239*f05cddf9SRui Paulo if (wps->dev.rf_bands == 0) { 1240*f05cddf9SRui Paulo /* 1241*f05cddf9SRui Paulo * Default to claiming support for both bands if the driver 1242*f05cddf9SRui Paulo * does not provide support for fetching supported bands. 1243*f05cddf9SRui Paulo */ 1244*f05cddf9SRui Paulo wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ; 1245*f05cddf9SRui Paulo } 124639beb93cSSam Leffler os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN); 1247*f05cddf9SRui Paulo wpas_wps_set_uuid(wpa_s, wps); 124839beb93cSSam Leffler 124939beb93cSSam Leffler wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK; 125039beb93cSSam Leffler wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP; 125139beb93cSSam Leffler 125239beb93cSSam Leffler os_memset(&rcfg, 0, sizeof(rcfg)); 125339beb93cSSam Leffler rcfg.new_psk_cb = wpas_wps_new_psk_cb; 125439beb93cSSam Leffler rcfg.pin_needed_cb = wpas_wps_pin_needed_cb; 1255e28a4053SRui Paulo rcfg.set_sel_reg_cb = wpas_wps_set_sel_reg_cb; 125639beb93cSSam Leffler rcfg.cb_ctx = wpa_s; 125739beb93cSSam Leffler 125839beb93cSSam Leffler wps->registrar = wps_registrar_init(wps, &rcfg); 125939beb93cSSam Leffler if (wps->registrar == NULL) { 126039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to initialize WPS Registrar"); 126139beb93cSSam Leffler os_free(wps); 126239beb93cSSam Leffler return -1; 126339beb93cSSam Leffler } 126439beb93cSSam Leffler 126539beb93cSSam Leffler wpa_s->wps = wps; 126639beb93cSSam Leffler 126739beb93cSSam Leffler return 0; 126839beb93cSSam Leffler } 126939beb93cSSam Leffler 127039beb93cSSam Leffler 127139beb93cSSam Leffler void wpas_wps_deinit(struct wpa_supplicant *wpa_s) 127239beb93cSSam Leffler { 127339beb93cSSam Leffler eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL); 1274*f05cddf9SRui Paulo eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL); 1275*f05cddf9SRui Paulo wpas_wps_clear_ap_info(wpa_s); 127639beb93cSSam Leffler 127739beb93cSSam Leffler if (wpa_s->wps == NULL) 127839beb93cSSam Leffler return; 127939beb93cSSam Leffler 1280e28a4053SRui Paulo #ifdef CONFIG_WPS_ER 1281e28a4053SRui Paulo wps_er_deinit(wpa_s->wps_er, NULL, NULL); 1282e28a4053SRui Paulo wpa_s->wps_er = NULL; 1283e28a4053SRui Paulo #endif /* CONFIG_WPS_ER */ 1284e28a4053SRui Paulo 128539beb93cSSam Leffler wps_registrar_deinit(wpa_s->wps->registrar); 1286e28a4053SRui Paulo wpabuf_free(wpa_s->wps->dh_pubkey); 1287e28a4053SRui Paulo wpabuf_free(wpa_s->wps->dh_privkey); 1288*f05cddf9SRui Paulo wpabuf_free(wpa_s->wps->dev.vendor_ext_m1); 128939beb93cSSam Leffler os_free(wpa_s->wps->network_key); 129039beb93cSSam Leffler os_free(wpa_s->wps); 129139beb93cSSam Leffler wpa_s->wps = NULL; 129239beb93cSSam Leffler } 129339beb93cSSam Leffler 129439beb93cSSam Leffler 129539beb93cSSam Leffler int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s, 1296*f05cddf9SRui Paulo struct wpa_ssid *ssid, struct wpa_bss *bss) 129739beb93cSSam Leffler { 129839beb93cSSam Leffler struct wpabuf *wps_ie; 129939beb93cSSam Leffler 130039beb93cSSam Leffler if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) 130139beb93cSSam Leffler return -1; 130239beb93cSSam Leffler 1303*f05cddf9SRui Paulo wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); 130439beb93cSSam Leffler if (eap_is_wps_pbc_enrollee(&ssid->eap)) { 130539beb93cSSam Leffler if (!wps_ie) { 130639beb93cSSam Leffler wpa_printf(MSG_DEBUG, " skip - non-WPS AP"); 130739beb93cSSam Leffler return 0; 130839beb93cSSam Leffler } 130939beb93cSSam Leffler 131039beb93cSSam Leffler if (!wps_is_selected_pbc_registrar(wps_ie)) { 131139beb93cSSam Leffler wpa_printf(MSG_DEBUG, " skip - WPS AP " 131239beb93cSSam Leffler "without active PBC Registrar"); 131339beb93cSSam Leffler wpabuf_free(wps_ie); 131439beb93cSSam Leffler return 0; 131539beb93cSSam Leffler } 131639beb93cSSam Leffler 131739beb93cSSam Leffler /* TODO: overlap detection */ 131839beb93cSSam Leffler wpa_printf(MSG_DEBUG, " selected based on WPS IE " 131939beb93cSSam Leffler "(Active PBC)"); 132039beb93cSSam Leffler wpabuf_free(wps_ie); 132139beb93cSSam Leffler return 1; 132239beb93cSSam Leffler } 132339beb93cSSam Leffler 132439beb93cSSam Leffler if (eap_is_wps_pin_enrollee(&ssid->eap)) { 132539beb93cSSam Leffler if (!wps_ie) { 132639beb93cSSam Leffler wpa_printf(MSG_DEBUG, " skip - non-WPS AP"); 132739beb93cSSam Leffler return 0; 132839beb93cSSam Leffler } 132939beb93cSSam Leffler 133039beb93cSSam Leffler /* 1331*f05cddf9SRui Paulo * Start with WPS APs that advertise our address as an 1332*f05cddf9SRui Paulo * authorized MAC (v2.0) or active PIN Registrar (v1.0) and 1333*f05cddf9SRui Paulo * allow any WPS AP after couple of scans since some APs do not 1334*f05cddf9SRui Paulo * set Selected Registrar attribute properly when using 1335*f05cddf9SRui Paulo * external Registrar. 133639beb93cSSam Leffler */ 1337*f05cddf9SRui Paulo if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) { 133839beb93cSSam Leffler if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) { 133939beb93cSSam Leffler wpa_printf(MSG_DEBUG, " skip - WPS AP " 134039beb93cSSam Leffler "without active PIN Registrar"); 134139beb93cSSam Leffler wpabuf_free(wps_ie); 134239beb93cSSam Leffler return 0; 134339beb93cSSam Leffler } 134439beb93cSSam Leffler wpa_printf(MSG_DEBUG, " selected based on WPS IE"); 134539beb93cSSam Leffler } else { 134639beb93cSSam Leffler wpa_printf(MSG_DEBUG, " selected based on WPS IE " 1347*f05cddf9SRui Paulo "(Authorized MAC or Active PIN)"); 134839beb93cSSam Leffler } 134939beb93cSSam Leffler wpabuf_free(wps_ie); 135039beb93cSSam Leffler return 1; 135139beb93cSSam Leffler } 135239beb93cSSam Leffler 135339beb93cSSam Leffler if (wps_ie) { 135439beb93cSSam Leffler wpa_printf(MSG_DEBUG, " selected based on WPS IE"); 135539beb93cSSam Leffler wpabuf_free(wps_ie); 135639beb93cSSam Leffler return 1; 135739beb93cSSam Leffler } 135839beb93cSSam Leffler 135939beb93cSSam Leffler return -1; 136039beb93cSSam Leffler } 136139beb93cSSam Leffler 136239beb93cSSam Leffler 136339beb93cSSam Leffler int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, 136439beb93cSSam Leffler struct wpa_ssid *ssid, 1365*f05cddf9SRui Paulo struct wpa_bss *bss) 136639beb93cSSam Leffler { 136739beb93cSSam Leffler struct wpabuf *wps_ie = NULL; 136839beb93cSSam Leffler int ret = 0; 136939beb93cSSam Leffler 137039beb93cSSam Leffler if (eap_is_wps_pbc_enrollee(&ssid->eap)) { 1371*f05cddf9SRui Paulo wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); 137239beb93cSSam Leffler if (wps_ie && wps_is_selected_pbc_registrar(wps_ie)) { 137339beb93cSSam Leffler /* allow wildcard SSID for WPS PBC */ 137439beb93cSSam Leffler ret = 1; 137539beb93cSSam Leffler } 137639beb93cSSam Leffler } else if (eap_is_wps_pin_enrollee(&ssid->eap)) { 1377*f05cddf9SRui Paulo wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); 137839beb93cSSam Leffler if (wps_ie && 1379*f05cddf9SRui Paulo (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1) || 138039beb93cSSam Leffler wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) { 138139beb93cSSam Leffler /* allow wildcard SSID for WPS PIN */ 138239beb93cSSam Leffler ret = 1; 138339beb93cSSam Leffler } 138439beb93cSSam Leffler } 138539beb93cSSam Leffler 138639beb93cSSam Leffler if (!ret && ssid->bssid_set && 138739beb93cSSam Leffler os_memcmp(ssid->bssid, bss->bssid, ETH_ALEN) == 0) { 138839beb93cSSam Leffler /* allow wildcard SSID due to hardcoded BSSID match */ 138939beb93cSSam Leffler ret = 1; 139039beb93cSSam Leffler } 139139beb93cSSam Leffler 1392*f05cddf9SRui Paulo #ifdef CONFIG_WPS_STRICT 1393*f05cddf9SRui Paulo if (wps_ie) { 1394*f05cddf9SRui Paulo if (wps_validate_beacon_probe_resp(wps_ie, bss->beacon_ie_len > 1395*f05cddf9SRui Paulo 0, bss->bssid) < 0) 1396*f05cddf9SRui Paulo ret = 0; 1397*f05cddf9SRui Paulo if (bss->beacon_ie_len) { 1398*f05cddf9SRui Paulo struct wpabuf *bcn_wps; 1399*f05cddf9SRui Paulo bcn_wps = wpa_bss_get_vendor_ie_multi_beacon( 1400*f05cddf9SRui Paulo bss, WPS_IE_VENDOR_TYPE); 1401*f05cddf9SRui Paulo if (bcn_wps == NULL) { 1402*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Mandatory WPS IE " 1403*f05cddf9SRui Paulo "missing from AP Beacon"); 1404*f05cddf9SRui Paulo ret = 0; 1405*f05cddf9SRui Paulo } else { 1406*f05cddf9SRui Paulo if (wps_validate_beacon(wps_ie) < 0) 1407*f05cddf9SRui Paulo ret = 0; 1408*f05cddf9SRui Paulo wpabuf_free(bcn_wps); 1409*f05cddf9SRui Paulo } 1410*f05cddf9SRui Paulo } 1411*f05cddf9SRui Paulo } 1412*f05cddf9SRui Paulo #endif /* CONFIG_WPS_STRICT */ 1413*f05cddf9SRui Paulo 141439beb93cSSam Leffler wpabuf_free(wps_ie); 141539beb93cSSam Leffler 141639beb93cSSam Leffler return ret; 141739beb93cSSam Leffler } 141839beb93cSSam Leffler 141939beb93cSSam Leffler 142039beb93cSSam Leffler int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, 1421e28a4053SRui Paulo struct wpa_bss *selected, struct wpa_ssid *ssid) 142239beb93cSSam Leffler { 142339beb93cSSam Leffler const u8 *sel_uuid, *uuid; 142439beb93cSSam Leffler struct wpabuf *wps_ie; 142539beb93cSSam Leffler int ret = 0; 1426e28a4053SRui Paulo struct wpa_bss *bss; 142739beb93cSSam Leffler 142839beb93cSSam Leffler if (!eap_is_wps_pbc_enrollee(&ssid->eap)) 142939beb93cSSam Leffler return 0; 143039beb93cSSam Leffler 1431*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Check whether PBC session overlap is " 1432*f05cddf9SRui Paulo "present in scan results; selected BSSID " MACSTR, 1433*f05cddf9SRui Paulo MAC2STR(selected->bssid)); 1434*f05cddf9SRui Paulo 143539beb93cSSam Leffler /* Make sure that only one AP is in active PBC mode */ 1436e28a4053SRui Paulo wps_ie = wpa_bss_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE); 1437*f05cddf9SRui Paulo if (wps_ie) { 143839beb93cSSam Leffler sel_uuid = wps_get_uuid_e(wps_ie); 1439*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: UUID of the selected BSS", 1440*f05cddf9SRui Paulo sel_uuid, UUID_LEN); 1441*f05cddf9SRui Paulo } else { 1442*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Selected BSS does not include " 1443*f05cddf9SRui Paulo "WPS IE?!"); 144439beb93cSSam Leffler sel_uuid = NULL; 1445*f05cddf9SRui Paulo } 144639beb93cSSam Leffler 1447e28a4053SRui Paulo dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 144839beb93cSSam Leffler struct wpabuf *ie; 144939beb93cSSam Leffler if (bss == selected) 145039beb93cSSam Leffler continue; 1451e28a4053SRui Paulo ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); 145239beb93cSSam Leffler if (!ie) 145339beb93cSSam Leffler continue; 145439beb93cSSam Leffler if (!wps_is_selected_pbc_registrar(ie)) { 145539beb93cSSam Leffler wpabuf_free(ie); 145639beb93cSSam Leffler continue; 145739beb93cSSam Leffler } 1458*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: " 1459*f05cddf9SRui Paulo MACSTR, MAC2STR(bss->bssid)); 146039beb93cSSam Leffler uuid = wps_get_uuid_e(ie); 1461*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS", 1462*f05cddf9SRui Paulo uuid, UUID_LEN); 146339beb93cSSam Leffler if (sel_uuid == NULL || uuid == NULL || 1464*f05cddf9SRui Paulo os_memcmp(sel_uuid, uuid, UUID_LEN) != 0) { 146539beb93cSSam Leffler ret = 1; /* PBC overlap */ 1466*f05cddf9SRui Paulo wpa_msg(wpa_s, MSG_INFO, "WPS: PBC overlap detected: " 1467*f05cddf9SRui Paulo MACSTR " and " MACSTR, 1468*f05cddf9SRui Paulo MAC2STR(selected->bssid), 1469*f05cddf9SRui Paulo MAC2STR(bss->bssid)); 147039beb93cSSam Leffler wpabuf_free(ie); 147139beb93cSSam Leffler break; 147239beb93cSSam Leffler } 147339beb93cSSam Leffler 147439beb93cSSam Leffler /* TODO: verify that this is reasonable dual-band situation */ 147539beb93cSSam Leffler 147639beb93cSSam Leffler wpabuf_free(ie); 147739beb93cSSam Leffler } 147839beb93cSSam Leffler 147939beb93cSSam Leffler wpabuf_free(wps_ie); 148039beb93cSSam Leffler 148139beb93cSSam Leffler return ret; 148239beb93cSSam Leffler } 148339beb93cSSam Leffler 148439beb93cSSam Leffler 148539beb93cSSam Leffler void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s) 148639beb93cSSam Leffler { 1487e28a4053SRui Paulo struct wpa_bss *bss; 1488*f05cddf9SRui Paulo unsigned int pbc = 0, auth = 0, pin = 0, wps = 0; 148939beb93cSSam Leffler 149039beb93cSSam Leffler if (wpa_s->disconnected || wpa_s->wpa_state >= WPA_ASSOCIATED) 149139beb93cSSam Leffler return; 149239beb93cSSam Leffler 1493e28a4053SRui Paulo dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 149439beb93cSSam Leffler struct wpabuf *ie; 1495e28a4053SRui Paulo ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); 149639beb93cSSam Leffler if (!ie) 149739beb93cSSam Leffler continue; 149839beb93cSSam Leffler if (wps_is_selected_pbc_registrar(ie)) 1499*f05cddf9SRui Paulo pbc++; 1500*f05cddf9SRui Paulo else if (wps_is_addr_authorized(ie, wpa_s->own_addr, 0)) 1501*f05cddf9SRui Paulo auth++; 150239beb93cSSam Leffler else if (wps_is_selected_pin_registrar(ie)) 1503*f05cddf9SRui Paulo pin++; 150439beb93cSSam Leffler else 1505*f05cddf9SRui Paulo wps++; 150639beb93cSSam Leffler wpabuf_free(ie); 150739beb93cSSam Leffler } 1508*f05cddf9SRui Paulo 1509*f05cddf9SRui Paulo if (pbc) 1510*f05cddf9SRui Paulo wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PBC); 1511*f05cddf9SRui Paulo else if (auth) 1512*f05cddf9SRui Paulo wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_AUTH); 1513*f05cddf9SRui Paulo else if (pin) 1514*f05cddf9SRui Paulo wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PIN); 1515*f05cddf9SRui Paulo else if (wps) 1516*f05cddf9SRui Paulo wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE); 151739beb93cSSam Leffler } 151839beb93cSSam Leffler 151939beb93cSSam Leffler 152039beb93cSSam Leffler int wpas_wps_searching(struct wpa_supplicant *wpa_s) 152139beb93cSSam Leffler { 152239beb93cSSam Leffler struct wpa_ssid *ssid; 152339beb93cSSam Leffler 152439beb93cSSam Leffler for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { 152539beb93cSSam Leffler if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && !ssid->disabled) 152639beb93cSSam Leffler return 1; 152739beb93cSSam Leffler } 152839beb93cSSam Leffler 152939beb93cSSam Leffler return 0; 153039beb93cSSam Leffler } 1531e28a4053SRui Paulo 1532e28a4053SRui Paulo 1533e28a4053SRui Paulo int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *buf, 1534e28a4053SRui Paulo char *end) 1535e28a4053SRui Paulo { 1536e28a4053SRui Paulo struct wpabuf *wps_ie; 1537e28a4053SRui Paulo int ret; 1538e28a4053SRui Paulo 1539e28a4053SRui Paulo wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, WPS_DEV_OUI_WFA); 1540e28a4053SRui Paulo if (wps_ie == NULL) 1541e28a4053SRui Paulo return 0; 1542e28a4053SRui Paulo 1543e28a4053SRui Paulo ret = wps_attr_text(wps_ie, buf, end); 1544e28a4053SRui Paulo wpabuf_free(wps_ie); 1545e28a4053SRui Paulo return ret; 1546e28a4053SRui Paulo } 1547e28a4053SRui Paulo 1548e28a4053SRui Paulo 1549*f05cddf9SRui Paulo int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter) 1550e28a4053SRui Paulo { 1551e28a4053SRui Paulo #ifdef CONFIG_WPS_ER 1552e28a4053SRui Paulo if (wpa_s->wps_er) { 1553e28a4053SRui Paulo wps_er_refresh(wpa_s->wps_er); 1554e28a4053SRui Paulo return 0; 1555e28a4053SRui Paulo } 1556*f05cddf9SRui Paulo wpa_s->wps_er = wps_er_init(wpa_s->wps, wpa_s->ifname, filter); 1557e28a4053SRui Paulo if (wpa_s->wps_er == NULL) 1558e28a4053SRui Paulo return -1; 1559e28a4053SRui Paulo return 0; 1560e28a4053SRui Paulo #else /* CONFIG_WPS_ER */ 1561e28a4053SRui Paulo return 0; 1562e28a4053SRui Paulo #endif /* CONFIG_WPS_ER */ 1563e28a4053SRui Paulo } 1564e28a4053SRui Paulo 1565e28a4053SRui Paulo 1566e28a4053SRui Paulo int wpas_wps_er_stop(struct wpa_supplicant *wpa_s) 1567e28a4053SRui Paulo { 1568e28a4053SRui Paulo #ifdef CONFIG_WPS_ER 1569e28a4053SRui Paulo wps_er_deinit(wpa_s->wps_er, NULL, NULL); 1570e28a4053SRui Paulo wpa_s->wps_er = NULL; 1571e28a4053SRui Paulo #endif /* CONFIG_WPS_ER */ 1572e28a4053SRui Paulo return 0; 1573e28a4053SRui Paulo } 1574e28a4053SRui Paulo 1575e28a4053SRui Paulo 1576e28a4053SRui Paulo #ifdef CONFIG_WPS_ER 1577*f05cddf9SRui Paulo int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr, 1578*f05cddf9SRui Paulo const char *uuid, const char *pin) 1579e28a4053SRui Paulo { 1580e28a4053SRui Paulo u8 u[UUID_LEN]; 1581e28a4053SRui Paulo int any = 0; 1582e28a4053SRui Paulo 1583e28a4053SRui Paulo if (os_strcmp(uuid, "any") == 0) 1584e28a4053SRui Paulo any = 1; 1585e28a4053SRui Paulo else if (uuid_str2bin(uuid, u)) 1586e28a4053SRui Paulo return -1; 1587*f05cddf9SRui Paulo return wps_registrar_add_pin(wpa_s->wps->registrar, addr, 1588*f05cddf9SRui Paulo any ? NULL : u, 1589e28a4053SRui Paulo (const u8 *) pin, os_strlen(pin), 300); 1590e28a4053SRui Paulo } 1591e28a4053SRui Paulo 1592e28a4053SRui Paulo 1593e28a4053SRui Paulo int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid) 1594e28a4053SRui Paulo { 1595e28a4053SRui Paulo u8 u[UUID_LEN]; 1596e28a4053SRui Paulo 1597e28a4053SRui Paulo if (uuid_str2bin(uuid, u)) 1598e28a4053SRui Paulo return -1; 1599e28a4053SRui Paulo return wps_er_pbc(wpa_s->wps_er, u); 1600e28a4053SRui Paulo } 1601e28a4053SRui Paulo 1602e28a4053SRui Paulo 1603e28a4053SRui Paulo int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid, 1604e28a4053SRui Paulo const char *pin) 1605e28a4053SRui Paulo { 1606e28a4053SRui Paulo u8 u[UUID_LEN]; 1607e28a4053SRui Paulo 1608e28a4053SRui Paulo if (uuid_str2bin(uuid, u)) 1609e28a4053SRui Paulo return -1; 1610e28a4053SRui Paulo return wps_er_learn(wpa_s->wps_er, u, (const u8 *) pin, 1611e28a4053SRui Paulo os_strlen(pin)); 1612e28a4053SRui Paulo } 1613e28a4053SRui Paulo 1614e28a4053SRui Paulo 1615*f05cddf9SRui Paulo int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid, 1616*f05cddf9SRui Paulo int id) 1617*f05cddf9SRui Paulo { 1618*f05cddf9SRui Paulo u8 u[UUID_LEN]; 1619*f05cddf9SRui Paulo struct wpa_ssid *ssid; 1620*f05cddf9SRui Paulo struct wps_credential cred; 1621*f05cddf9SRui Paulo 1622*f05cddf9SRui Paulo if (uuid_str2bin(uuid, u)) 1623*f05cddf9SRui Paulo return -1; 1624*f05cddf9SRui Paulo ssid = wpa_config_get_network(wpa_s->conf, id); 1625*f05cddf9SRui Paulo if (ssid == NULL || ssid->ssid == NULL) 1626*f05cddf9SRui Paulo return -1; 1627*f05cddf9SRui Paulo 1628*f05cddf9SRui Paulo os_memset(&cred, 0, sizeof(cred)); 1629*f05cddf9SRui Paulo if (ssid->ssid_len > 32) 1630*f05cddf9SRui Paulo return -1; 1631*f05cddf9SRui Paulo os_memcpy(cred.ssid, ssid->ssid, ssid->ssid_len); 1632*f05cddf9SRui Paulo cred.ssid_len = ssid->ssid_len; 1633*f05cddf9SRui Paulo if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { 1634*f05cddf9SRui Paulo cred.auth_type = (ssid->proto & WPA_PROTO_RSN) ? 1635*f05cddf9SRui Paulo WPS_AUTH_WPA2PSK : WPS_AUTH_WPAPSK; 1636*f05cddf9SRui Paulo if (ssid->pairwise_cipher & WPA_CIPHER_CCMP) 1637*f05cddf9SRui Paulo cred.encr_type = WPS_ENCR_AES; 1638*f05cddf9SRui Paulo else 1639*f05cddf9SRui Paulo cred.encr_type = WPS_ENCR_TKIP; 1640*f05cddf9SRui Paulo if (ssid->passphrase) { 1641*f05cddf9SRui Paulo cred.key_len = os_strlen(ssid->passphrase); 1642*f05cddf9SRui Paulo if (cred.key_len >= 64) 1643*f05cddf9SRui Paulo return -1; 1644*f05cddf9SRui Paulo os_memcpy(cred.key, ssid->passphrase, cred.key_len); 1645*f05cddf9SRui Paulo } else if (ssid->psk_set) { 1646*f05cddf9SRui Paulo cred.key_len = 32; 1647*f05cddf9SRui Paulo os_memcpy(cred.key, ssid->psk, 32); 1648*f05cddf9SRui Paulo } else 1649*f05cddf9SRui Paulo return -1; 1650*f05cddf9SRui Paulo } else { 1651*f05cddf9SRui Paulo cred.auth_type = WPS_AUTH_OPEN; 1652*f05cddf9SRui Paulo cred.encr_type = WPS_ENCR_NONE; 1653*f05cddf9SRui Paulo } 1654*f05cddf9SRui Paulo return wps_er_set_config(wpa_s->wps_er, u, &cred); 1655*f05cddf9SRui Paulo } 1656*f05cddf9SRui Paulo 1657*f05cddf9SRui Paulo 1658*f05cddf9SRui Paulo int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid, 1659*f05cddf9SRui Paulo const char *pin, struct wps_new_ap_settings *settings) 1660*f05cddf9SRui Paulo { 1661*f05cddf9SRui Paulo u8 u[UUID_LEN]; 1662*f05cddf9SRui Paulo struct wps_credential cred; 1663*f05cddf9SRui Paulo size_t len; 1664*f05cddf9SRui Paulo 1665*f05cddf9SRui Paulo if (uuid_str2bin(uuid, u)) 1666*f05cddf9SRui Paulo return -1; 1667*f05cddf9SRui Paulo if (settings->ssid_hex == NULL || settings->auth == NULL || 1668*f05cddf9SRui Paulo settings->encr == NULL || settings->key_hex == NULL) 1669*f05cddf9SRui Paulo return -1; 1670*f05cddf9SRui Paulo 1671*f05cddf9SRui Paulo os_memset(&cred, 0, sizeof(cred)); 1672*f05cddf9SRui Paulo len = os_strlen(settings->ssid_hex); 1673*f05cddf9SRui Paulo if ((len & 1) || len > 2 * sizeof(cred.ssid) || 1674*f05cddf9SRui Paulo hexstr2bin(settings->ssid_hex, cred.ssid, len / 2)) 1675*f05cddf9SRui Paulo return -1; 1676*f05cddf9SRui Paulo cred.ssid_len = len / 2; 1677*f05cddf9SRui Paulo 1678*f05cddf9SRui Paulo len = os_strlen(settings->key_hex); 1679*f05cddf9SRui Paulo if ((len & 1) || len > 2 * sizeof(cred.key) || 1680*f05cddf9SRui Paulo hexstr2bin(settings->key_hex, cred.key, len / 2)) 1681*f05cddf9SRui Paulo return -1; 1682*f05cddf9SRui Paulo cred.key_len = len / 2; 1683*f05cddf9SRui Paulo 1684*f05cddf9SRui Paulo if (os_strcmp(settings->auth, "OPEN") == 0) 1685*f05cddf9SRui Paulo cred.auth_type = WPS_AUTH_OPEN; 1686*f05cddf9SRui Paulo else if (os_strcmp(settings->auth, "WPAPSK") == 0) 1687*f05cddf9SRui Paulo cred.auth_type = WPS_AUTH_WPAPSK; 1688*f05cddf9SRui Paulo else if (os_strcmp(settings->auth, "WPA2PSK") == 0) 1689*f05cddf9SRui Paulo cred.auth_type = WPS_AUTH_WPA2PSK; 1690*f05cddf9SRui Paulo else 1691*f05cddf9SRui Paulo return -1; 1692*f05cddf9SRui Paulo 1693*f05cddf9SRui Paulo if (os_strcmp(settings->encr, "NONE") == 0) 1694*f05cddf9SRui Paulo cred.encr_type = WPS_ENCR_NONE; 1695*f05cddf9SRui Paulo else if (os_strcmp(settings->encr, "WEP") == 0) 1696*f05cddf9SRui Paulo cred.encr_type = WPS_ENCR_WEP; 1697*f05cddf9SRui Paulo else if (os_strcmp(settings->encr, "TKIP") == 0) 1698*f05cddf9SRui Paulo cred.encr_type = WPS_ENCR_TKIP; 1699*f05cddf9SRui Paulo else if (os_strcmp(settings->encr, "CCMP") == 0) 1700*f05cddf9SRui Paulo cred.encr_type = WPS_ENCR_AES; 1701*f05cddf9SRui Paulo else 1702*f05cddf9SRui Paulo return -1; 1703*f05cddf9SRui Paulo 1704*f05cddf9SRui Paulo return wps_er_config(wpa_s->wps_er, u, (const u8 *) pin, 1705*f05cddf9SRui Paulo os_strlen(pin), &cred); 1706*f05cddf9SRui Paulo } 1707*f05cddf9SRui Paulo 1708*f05cddf9SRui Paulo 1709*f05cddf9SRui Paulo #ifdef CONFIG_WPS_NFC 1710*f05cddf9SRui Paulo struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s, 1711*f05cddf9SRui Paulo int ndef, const char *uuid) 1712*f05cddf9SRui Paulo { 1713*f05cddf9SRui Paulo struct wpabuf *ret; 1714*f05cddf9SRui Paulo u8 u[UUID_LEN]; 1715*f05cddf9SRui Paulo 1716*f05cddf9SRui Paulo if (!wpa_s->wps_er) 1717*f05cddf9SRui Paulo return NULL; 1718*f05cddf9SRui Paulo 1719*f05cddf9SRui Paulo if (uuid_str2bin(uuid, u)) 1720*f05cddf9SRui Paulo return NULL; 1721*f05cddf9SRui Paulo 1722*f05cddf9SRui Paulo ret = wps_er_nfc_config_token(wpa_s->wps_er, u); 1723*f05cddf9SRui Paulo if (ndef && ret) { 1724*f05cddf9SRui Paulo struct wpabuf *tmp; 1725*f05cddf9SRui Paulo tmp = ndef_build_wifi(ret); 1726*f05cddf9SRui Paulo wpabuf_free(ret); 1727*f05cddf9SRui Paulo if (tmp == NULL) 1728*f05cddf9SRui Paulo return NULL; 1729*f05cddf9SRui Paulo ret = tmp; 1730*f05cddf9SRui Paulo } 1731*f05cddf9SRui Paulo 1732*f05cddf9SRui Paulo return ret; 1733*f05cddf9SRui Paulo } 1734*f05cddf9SRui Paulo #endif /* CONFIG_WPS_NFC */ 1735*f05cddf9SRui Paulo 1736*f05cddf9SRui Paulo 1737*f05cddf9SRui Paulo static int callbacks_pending = 0; 1738*f05cddf9SRui Paulo 1739e28a4053SRui Paulo static void wpas_wps_terminate_cb(void *ctx) 1740e28a4053SRui Paulo { 1741e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS ER: Terminated"); 1742*f05cddf9SRui Paulo if (--callbacks_pending <= 0) 1743e28a4053SRui Paulo eloop_terminate(); 1744e28a4053SRui Paulo } 1745e28a4053SRui Paulo #endif /* CONFIG_WPS_ER */ 1746e28a4053SRui Paulo 1747e28a4053SRui Paulo 1748e28a4053SRui Paulo int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s) 1749e28a4053SRui Paulo { 1750e28a4053SRui Paulo #ifdef CONFIG_WPS_ER 1751e28a4053SRui Paulo if (wpa_s->wps_er) { 1752*f05cddf9SRui Paulo callbacks_pending++; 1753e28a4053SRui Paulo wps_er_deinit(wpa_s->wps_er, wpas_wps_terminate_cb, wpa_s); 1754e28a4053SRui Paulo wpa_s->wps_er = NULL; 1755e28a4053SRui Paulo return 1; 1756e28a4053SRui Paulo } 1757e28a4053SRui Paulo #endif /* CONFIG_WPS_ER */ 1758e28a4053SRui Paulo return 0; 1759e28a4053SRui Paulo } 1760*f05cddf9SRui Paulo 1761*f05cddf9SRui Paulo 1762*f05cddf9SRui Paulo int wpas_wps_in_progress(struct wpa_supplicant *wpa_s) 1763*f05cddf9SRui Paulo { 1764*f05cddf9SRui Paulo struct wpa_ssid *ssid; 1765*f05cddf9SRui Paulo 1766*f05cddf9SRui Paulo for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { 1767*f05cddf9SRui Paulo if (!ssid->disabled && ssid->key_mgmt == WPA_KEY_MGMT_WPS) 1768*f05cddf9SRui Paulo return 1; 1769*f05cddf9SRui Paulo } 1770*f05cddf9SRui Paulo 1771*f05cddf9SRui Paulo return 0; 1772*f05cddf9SRui Paulo } 1773*f05cddf9SRui Paulo 1774*f05cddf9SRui Paulo 1775*f05cddf9SRui Paulo void wpas_wps_update_config(struct wpa_supplicant *wpa_s) 1776*f05cddf9SRui Paulo { 1777*f05cddf9SRui Paulo struct wps_context *wps = wpa_s->wps; 1778*f05cddf9SRui Paulo 1779*f05cddf9SRui Paulo if (wps == NULL) 1780*f05cddf9SRui Paulo return; 1781*f05cddf9SRui Paulo 1782*f05cddf9SRui Paulo if (wpa_s->conf->changed_parameters & CFG_CHANGED_CONFIG_METHODS) { 1783*f05cddf9SRui Paulo wps->config_methods = wps_config_methods_str2bin( 1784*f05cddf9SRui Paulo wpa_s->conf->config_methods); 1785*f05cddf9SRui Paulo if ((wps->config_methods & 1786*f05cddf9SRui Paulo (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) == 1787*f05cddf9SRui Paulo (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) { 1788*f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "WPS: Both Label and Display " 1789*f05cddf9SRui Paulo "config methods are not allowed at the " 1790*f05cddf9SRui Paulo "same time"); 1791*f05cddf9SRui Paulo wps->config_methods &= ~WPS_CONFIG_LABEL; 1792*f05cddf9SRui Paulo } 1793*f05cddf9SRui Paulo } 1794*f05cddf9SRui Paulo wps->config_methods = wps_fix_config_methods(wps->config_methods); 1795*f05cddf9SRui Paulo wps->dev.config_methods = wps->config_methods; 1796*f05cddf9SRui Paulo 1797*f05cddf9SRui Paulo if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE) 1798*f05cddf9SRui Paulo os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type, 1799*f05cddf9SRui Paulo WPS_DEV_TYPE_LEN); 1800*f05cddf9SRui Paulo 1801*f05cddf9SRui Paulo if (wpa_s->conf->changed_parameters & CFG_CHANGED_SEC_DEVICE_TYPE) { 1802*f05cddf9SRui Paulo wps->dev.num_sec_dev_types = wpa_s->conf->num_sec_device_types; 1803*f05cddf9SRui Paulo os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type, 1804*f05cddf9SRui Paulo wps->dev.num_sec_dev_types * WPS_DEV_TYPE_LEN); 1805*f05cddf9SRui Paulo } 1806*f05cddf9SRui Paulo 1807*f05cddf9SRui Paulo if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION) 1808*f05cddf9SRui Paulo wpas_wps_set_vendor_ext_m1(wpa_s, wps); 1809*f05cddf9SRui Paulo 1810*f05cddf9SRui Paulo if (wpa_s->conf->changed_parameters & CFG_CHANGED_OS_VERSION) 1811*f05cddf9SRui Paulo wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version); 1812*f05cddf9SRui Paulo 1813*f05cddf9SRui Paulo if (wpa_s->conf->changed_parameters & CFG_CHANGED_UUID) 1814*f05cddf9SRui Paulo wpas_wps_set_uuid(wpa_s, wps); 1815*f05cddf9SRui Paulo 1816*f05cddf9SRui Paulo if (wpa_s->conf->changed_parameters & 1817*f05cddf9SRui Paulo (CFG_CHANGED_DEVICE_NAME | CFG_CHANGED_WPS_STRING)) { 1818*f05cddf9SRui Paulo /* Update pointers to make sure they refer current values */ 1819*f05cddf9SRui Paulo wps->dev.device_name = wpa_s->conf->device_name; 1820*f05cddf9SRui Paulo wps->dev.manufacturer = wpa_s->conf->manufacturer; 1821*f05cddf9SRui Paulo wps->dev.model_name = wpa_s->conf->model_name; 1822*f05cddf9SRui Paulo wps->dev.model_number = wpa_s->conf->model_number; 1823*f05cddf9SRui Paulo wps->dev.serial_number = wpa_s->conf->serial_number; 1824*f05cddf9SRui Paulo } 1825*f05cddf9SRui Paulo } 1826*f05cddf9SRui Paulo 1827*f05cddf9SRui Paulo 1828*f05cddf9SRui Paulo #ifdef CONFIG_WPS_NFC 1829*f05cddf9SRui Paulo 1830*f05cddf9SRui Paulo struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef) 1831*f05cddf9SRui Paulo { 1832*f05cddf9SRui Paulo return wps_nfc_token_gen(ndef, &wpa_s->conf->wps_nfc_dev_pw_id, 1833*f05cddf9SRui Paulo &wpa_s->conf->wps_nfc_dh_pubkey, 1834*f05cddf9SRui Paulo &wpa_s->conf->wps_nfc_dh_privkey, 1835*f05cddf9SRui Paulo &wpa_s->conf->wps_nfc_dev_pw); 1836*f05cddf9SRui Paulo } 1837*f05cddf9SRui Paulo 1838*f05cddf9SRui Paulo 1839*f05cddf9SRui Paulo int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid) 1840*f05cddf9SRui Paulo { 1841*f05cddf9SRui Paulo struct wps_context *wps = wpa_s->wps; 1842*f05cddf9SRui Paulo char pw[32 * 2 + 1]; 1843*f05cddf9SRui Paulo 1844*f05cddf9SRui Paulo if (wpa_s->conf->wps_nfc_dh_pubkey == NULL || 1845*f05cddf9SRui Paulo wpa_s->conf->wps_nfc_dh_privkey == NULL || 1846*f05cddf9SRui Paulo wpa_s->conf->wps_nfc_dev_pw == NULL) 1847*f05cddf9SRui Paulo return -1; 1848*f05cddf9SRui Paulo 1849*f05cddf9SRui Paulo dh5_free(wps->dh_ctx); 1850*f05cddf9SRui Paulo wpabuf_free(wps->dh_pubkey); 1851*f05cddf9SRui Paulo wpabuf_free(wps->dh_privkey); 1852*f05cddf9SRui Paulo wps->dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey); 1853*f05cddf9SRui Paulo wps->dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey); 1854*f05cddf9SRui Paulo if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) { 1855*f05cddf9SRui Paulo wps->dh_ctx = NULL; 1856*f05cddf9SRui Paulo wpabuf_free(wps->dh_pubkey); 1857*f05cddf9SRui Paulo wps->dh_pubkey = NULL; 1858*f05cddf9SRui Paulo wpabuf_free(wps->dh_privkey); 1859*f05cddf9SRui Paulo wps->dh_privkey = NULL; 1860*f05cddf9SRui Paulo return -1; 1861*f05cddf9SRui Paulo } 1862*f05cddf9SRui Paulo wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey); 1863*f05cddf9SRui Paulo if (wps->dh_ctx == NULL) 1864*f05cddf9SRui Paulo return -1; 1865*f05cddf9SRui Paulo 1866*f05cddf9SRui Paulo wpa_snprintf_hex_uppercase(pw, sizeof(pw), 1867*f05cddf9SRui Paulo wpabuf_head(wpa_s->conf->wps_nfc_dev_pw), 1868*f05cddf9SRui Paulo wpabuf_len(wpa_s->conf->wps_nfc_dev_pw)); 1869*f05cddf9SRui Paulo return wpas_wps_start_pin(wpa_s, bssid, pw, 0, 1870*f05cddf9SRui Paulo wpa_s->conf->wps_nfc_dev_pw_id); 1871*f05cddf9SRui Paulo } 1872*f05cddf9SRui Paulo 1873*f05cddf9SRui Paulo 1874*f05cddf9SRui Paulo static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s, 1875*f05cddf9SRui Paulo struct wps_parse_attr *attr) 1876*f05cddf9SRui Paulo { 1877*f05cddf9SRui Paulo wpa_s->wps_ap_channel = 0; 1878*f05cddf9SRui Paulo 1879*f05cddf9SRui Paulo if (wps_oob_use_cred(wpa_s->wps, attr) < 0) 1880*f05cddf9SRui Paulo return -1; 1881*f05cddf9SRui Paulo 1882*f05cddf9SRui Paulo if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) 1883*f05cddf9SRui Paulo return 0; 1884*f05cddf9SRui Paulo 1885*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Request reconnection with new network " 1886*f05cddf9SRui Paulo "based on the received credential added"); 1887*f05cddf9SRui Paulo wpa_s->normal_scans = 0; 1888*f05cddf9SRui Paulo wpa_supplicant_reinit_autoscan(wpa_s); 1889*f05cddf9SRui Paulo if (wpa_s->wps_ap_channel) { 1890*f05cddf9SRui Paulo u16 chan = wpa_s->wps_ap_channel; 1891*f05cddf9SRui Paulo int freq = 0; 1892*f05cddf9SRui Paulo 1893*f05cddf9SRui Paulo if (chan >= 1 && chan <= 13) 1894*f05cddf9SRui Paulo freq = 2407 + 5 * chan; 1895*f05cddf9SRui Paulo else if (chan == 14) 1896*f05cddf9SRui Paulo freq = 2484; 1897*f05cddf9SRui Paulo else if (chan >= 30) 1898*f05cddf9SRui Paulo freq = 5000 + 5 * chan; 1899*f05cddf9SRui Paulo 1900*f05cddf9SRui Paulo if (freq) { 1901*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Credential indicated " 1902*f05cddf9SRui Paulo "AP channel %u -> %u MHz", chan, freq); 1903*f05cddf9SRui Paulo wpa_s->after_wps = 5; 1904*f05cddf9SRui Paulo wpa_s->wps_freq = freq; 1905*f05cddf9SRui Paulo } 1906*f05cddf9SRui Paulo } 1907*f05cddf9SRui Paulo wpa_s->disconnected = 0; 1908*f05cddf9SRui Paulo wpa_s->reassociate = 1; 1909*f05cddf9SRui Paulo wpa_supplicant_req_scan(wpa_s, 0, 0); 1910*f05cddf9SRui Paulo 1911*f05cddf9SRui Paulo return 0; 1912*f05cddf9SRui Paulo } 1913*f05cddf9SRui Paulo 1914*f05cddf9SRui Paulo 1915*f05cddf9SRui Paulo #ifdef CONFIG_WPS_ER 1916*f05cddf9SRui Paulo static int wpas_wps_add_nfc_password_token(struct wpa_supplicant *wpa_s, 1917*f05cddf9SRui Paulo struct wps_parse_attr *attr) 1918*f05cddf9SRui Paulo { 1919*f05cddf9SRui Paulo return wps_registrar_add_nfc_password_token( 1920*f05cddf9SRui Paulo wpa_s->wps->registrar, attr->oob_dev_password, 1921*f05cddf9SRui Paulo attr->oob_dev_password_len); 1922*f05cddf9SRui Paulo } 1923*f05cddf9SRui Paulo #endif /* CONFIG_WPS_ER */ 1924*f05cddf9SRui Paulo 1925*f05cddf9SRui Paulo 1926*f05cddf9SRui Paulo static int wpas_wps_nfc_tag_process(struct wpa_supplicant *wpa_s, 1927*f05cddf9SRui Paulo const struct wpabuf *wps) 1928*f05cddf9SRui Paulo { 1929*f05cddf9SRui Paulo struct wps_parse_attr attr; 1930*f05cddf9SRui Paulo 1931*f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps); 1932*f05cddf9SRui Paulo 1933*f05cddf9SRui Paulo if (wps_parse_msg(wps, &attr)) { 1934*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag"); 1935*f05cddf9SRui Paulo return -1; 1936*f05cddf9SRui Paulo } 1937*f05cddf9SRui Paulo 1938*f05cddf9SRui Paulo if (attr.num_cred) 1939*f05cddf9SRui Paulo return wpas_wps_use_cred(wpa_s, &attr); 1940*f05cddf9SRui Paulo 1941*f05cddf9SRui Paulo #ifdef CONFIG_WPS_ER 1942*f05cddf9SRui Paulo if (attr.oob_dev_password) 1943*f05cddf9SRui Paulo return wpas_wps_add_nfc_password_token(wpa_s, &attr); 1944*f05cddf9SRui Paulo #endif /* CONFIG_WPS_ER */ 1945*f05cddf9SRui Paulo 1946*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag"); 1947*f05cddf9SRui Paulo return -1; 1948*f05cddf9SRui Paulo } 1949*f05cddf9SRui Paulo 1950*f05cddf9SRui Paulo 1951*f05cddf9SRui Paulo int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s, 1952*f05cddf9SRui Paulo const struct wpabuf *data) 1953*f05cddf9SRui Paulo { 1954*f05cddf9SRui Paulo const struct wpabuf *wps = data; 1955*f05cddf9SRui Paulo struct wpabuf *tmp = NULL; 1956*f05cddf9SRui Paulo int ret; 1957*f05cddf9SRui Paulo 1958*f05cddf9SRui Paulo if (wpabuf_len(data) < 4) 1959*f05cddf9SRui Paulo return -1; 1960*f05cddf9SRui Paulo 1961*f05cddf9SRui Paulo if (*wpabuf_head_u8(data) != 0x10) { 1962*f05cddf9SRui Paulo /* Assume this contains full NDEF record */ 1963*f05cddf9SRui Paulo tmp = ndef_parse_wifi(data); 1964*f05cddf9SRui Paulo if (tmp == NULL) { 1965*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF"); 1966*f05cddf9SRui Paulo return -1; 1967*f05cddf9SRui Paulo } 1968*f05cddf9SRui Paulo wps = tmp; 1969*f05cddf9SRui Paulo } 1970*f05cddf9SRui Paulo 1971*f05cddf9SRui Paulo ret = wpas_wps_nfc_tag_process(wpa_s, wps); 1972*f05cddf9SRui Paulo wpabuf_free(tmp); 1973*f05cddf9SRui Paulo return ret; 1974*f05cddf9SRui Paulo } 1975*f05cddf9SRui Paulo 1976*f05cddf9SRui Paulo 1977*f05cddf9SRui Paulo struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s) 1978*f05cddf9SRui Paulo { 1979*f05cddf9SRui Paulo return ndef_build_wifi_hr(); 1980*f05cddf9SRui Paulo } 1981*f05cddf9SRui Paulo 1982*f05cddf9SRui Paulo 1983*f05cddf9SRui Paulo struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s) 1984*f05cddf9SRui Paulo { 1985*f05cddf9SRui Paulo return NULL; 1986*f05cddf9SRui Paulo } 1987*f05cddf9SRui Paulo 1988*f05cddf9SRui Paulo 1989*f05cddf9SRui Paulo int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s, 1990*f05cddf9SRui Paulo const struct wpabuf *data) 1991*f05cddf9SRui Paulo { 1992*f05cddf9SRui Paulo /* TODO */ 1993*f05cddf9SRui Paulo return -1; 1994*f05cddf9SRui Paulo } 1995*f05cddf9SRui Paulo 1996*f05cddf9SRui Paulo 1997*f05cddf9SRui Paulo int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s, 1998*f05cddf9SRui Paulo const struct wpabuf *data) 1999*f05cddf9SRui Paulo { 2000*f05cddf9SRui Paulo struct wpabuf *wps; 2001*f05cddf9SRui Paulo int ret; 2002*f05cddf9SRui Paulo 2003*f05cddf9SRui Paulo wps = ndef_parse_wifi(data); 2004*f05cddf9SRui Paulo if (wps == NULL) 2005*f05cddf9SRui Paulo return -1; 2006*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc " 2007*f05cddf9SRui Paulo "payload from NFC connection handover"); 2008*f05cddf9SRui Paulo wpa_hexdump_buf_key(MSG_DEBUG, "WPS: NFC payload", wps); 2009*f05cddf9SRui Paulo ret = wpas_wps_nfc_tag_process(wpa_s, wps); 2010*f05cddf9SRui Paulo wpabuf_free(wps); 2011*f05cddf9SRui Paulo 2012*f05cddf9SRui Paulo return ret; 2013*f05cddf9SRui Paulo } 2014*f05cddf9SRui Paulo 2015*f05cddf9SRui Paulo #endif /* CONFIG_WPS_NFC */ 2016*f05cddf9SRui Paulo 2017*f05cddf9SRui Paulo 2018*f05cddf9SRui Paulo extern int wpa_debug_level; 2019*f05cddf9SRui Paulo 2020*f05cddf9SRui Paulo static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s) 2021*f05cddf9SRui Paulo { 2022*f05cddf9SRui Paulo size_t i; 2023*f05cddf9SRui Paulo struct os_time now; 2024*f05cddf9SRui Paulo 2025*f05cddf9SRui Paulo if (wpa_debug_level > MSG_DEBUG) 2026*f05cddf9SRui Paulo return; 2027*f05cddf9SRui Paulo 2028*f05cddf9SRui Paulo if (wpa_s->wps_ap == NULL) 2029*f05cddf9SRui Paulo return; 2030*f05cddf9SRui Paulo 2031*f05cddf9SRui Paulo os_get_time(&now); 2032*f05cddf9SRui Paulo 2033*f05cddf9SRui Paulo for (i = 0; i < wpa_s->num_wps_ap; i++) { 2034*f05cddf9SRui Paulo struct wps_ap_info *ap = &wpa_s->wps_ap[i]; 2035*f05cddf9SRui Paulo struct wpa_blacklist *e = wpa_blacklist_get(wpa_s, ap->bssid); 2036*f05cddf9SRui Paulo 2037*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: AP[%d] " MACSTR " type=%d " 2038*f05cddf9SRui Paulo "tries=%d last_attempt=%d sec ago blacklist=%d", 2039*f05cddf9SRui Paulo (int) i, MAC2STR(ap->bssid), ap->type, ap->tries, 2040*f05cddf9SRui Paulo ap->last_attempt.sec > 0 ? 2041*f05cddf9SRui Paulo (int) now.sec - (int) ap->last_attempt.sec : -1, 2042*f05cddf9SRui Paulo e ? e->count : 0); 2043*f05cddf9SRui Paulo } 2044*f05cddf9SRui Paulo } 2045*f05cddf9SRui Paulo 2046*f05cddf9SRui Paulo 2047*f05cddf9SRui Paulo static struct wps_ap_info * wpas_wps_get_ap_info(struct wpa_supplicant *wpa_s, 2048*f05cddf9SRui Paulo const u8 *bssid) 2049*f05cddf9SRui Paulo { 2050*f05cddf9SRui Paulo size_t i; 2051*f05cddf9SRui Paulo 2052*f05cddf9SRui Paulo if (wpa_s->wps_ap == NULL) 2053*f05cddf9SRui Paulo return NULL; 2054*f05cddf9SRui Paulo 2055*f05cddf9SRui Paulo for (i = 0; i < wpa_s->num_wps_ap; i++) { 2056*f05cddf9SRui Paulo struct wps_ap_info *ap = &wpa_s->wps_ap[i]; 2057*f05cddf9SRui Paulo if (os_memcmp(ap->bssid, bssid, ETH_ALEN) == 0) 2058*f05cddf9SRui Paulo return ap; 2059*f05cddf9SRui Paulo } 2060*f05cddf9SRui Paulo 2061*f05cddf9SRui Paulo return NULL; 2062*f05cddf9SRui Paulo } 2063*f05cddf9SRui Paulo 2064*f05cddf9SRui Paulo 2065*f05cddf9SRui Paulo static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s, 2066*f05cddf9SRui Paulo struct wpa_scan_res *res) 2067*f05cddf9SRui Paulo { 2068*f05cddf9SRui Paulo struct wpabuf *wps; 2069*f05cddf9SRui Paulo enum wps_ap_info_type type; 2070*f05cddf9SRui Paulo struct wps_ap_info *ap; 2071*f05cddf9SRui Paulo int r; 2072*f05cddf9SRui Paulo 2073*f05cddf9SRui Paulo if (wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE) == NULL) 2074*f05cddf9SRui Paulo return; 2075*f05cddf9SRui Paulo 2076*f05cddf9SRui Paulo wps = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE); 2077*f05cddf9SRui Paulo if (wps == NULL) 2078*f05cddf9SRui Paulo return; 2079*f05cddf9SRui Paulo 2080*f05cddf9SRui Paulo r = wps_is_addr_authorized(wps, wpa_s->own_addr, 1); 2081*f05cddf9SRui Paulo if (r == 2) 2082*f05cddf9SRui Paulo type = WPS_AP_SEL_REG_OUR; 2083*f05cddf9SRui Paulo else if (r == 1) 2084*f05cddf9SRui Paulo type = WPS_AP_SEL_REG; 2085*f05cddf9SRui Paulo else 2086*f05cddf9SRui Paulo type = WPS_AP_NOT_SEL_REG; 2087*f05cddf9SRui Paulo 2088*f05cddf9SRui Paulo wpabuf_free(wps); 2089*f05cddf9SRui Paulo 2090*f05cddf9SRui Paulo ap = wpas_wps_get_ap_info(wpa_s, res->bssid); 2091*f05cddf9SRui Paulo if (ap) { 2092*f05cddf9SRui Paulo if (ap->type != type) { 2093*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR 2094*f05cddf9SRui Paulo " changed type %d -> %d", 2095*f05cddf9SRui Paulo MAC2STR(res->bssid), ap->type, type); 2096*f05cddf9SRui Paulo ap->type = type; 2097*f05cddf9SRui Paulo if (type != WPS_AP_NOT_SEL_REG) 2098*f05cddf9SRui Paulo wpa_blacklist_del(wpa_s, ap->bssid); 2099*f05cddf9SRui Paulo } 2100*f05cddf9SRui Paulo return; 2101*f05cddf9SRui Paulo } 2102*f05cddf9SRui Paulo 2103*f05cddf9SRui Paulo ap = os_realloc_array(wpa_s->wps_ap, wpa_s->num_wps_ap + 1, 2104*f05cddf9SRui Paulo sizeof(struct wps_ap_info)); 2105*f05cddf9SRui Paulo if (ap == NULL) 2106*f05cddf9SRui Paulo return; 2107*f05cddf9SRui Paulo 2108*f05cddf9SRui Paulo wpa_s->wps_ap = ap; 2109*f05cddf9SRui Paulo ap = &wpa_s->wps_ap[wpa_s->num_wps_ap]; 2110*f05cddf9SRui Paulo wpa_s->num_wps_ap++; 2111*f05cddf9SRui Paulo 2112*f05cddf9SRui Paulo os_memset(ap, 0, sizeof(*ap)); 2113*f05cddf9SRui Paulo os_memcpy(ap->bssid, res->bssid, ETH_ALEN); 2114*f05cddf9SRui Paulo ap->type = type; 2115*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " type %d added", 2116*f05cddf9SRui Paulo MAC2STR(ap->bssid), ap->type); 2117*f05cddf9SRui Paulo } 2118*f05cddf9SRui Paulo 2119*f05cddf9SRui Paulo 2120*f05cddf9SRui Paulo void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s, 2121*f05cddf9SRui Paulo struct wpa_scan_results *scan_res) 2122*f05cddf9SRui Paulo { 2123*f05cddf9SRui Paulo size_t i; 2124*f05cddf9SRui Paulo 2125*f05cddf9SRui Paulo for (i = 0; i < scan_res->num; i++) 2126*f05cddf9SRui Paulo wpas_wps_update_ap_info_bss(wpa_s, scan_res->res[i]); 2127*f05cddf9SRui Paulo 2128*f05cddf9SRui Paulo wpas_wps_dump_ap_info(wpa_s); 2129*f05cddf9SRui Paulo } 2130*f05cddf9SRui Paulo 2131*f05cddf9SRui Paulo 2132*f05cddf9SRui Paulo void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid) 2133*f05cddf9SRui Paulo { 2134*f05cddf9SRui Paulo struct wps_ap_info *ap; 2135*f05cddf9SRui Paulo if (!wpa_s->wps_ap_iter) 2136*f05cddf9SRui Paulo return; 2137*f05cddf9SRui Paulo ap = wpas_wps_get_ap_info(wpa_s, bssid); 2138*f05cddf9SRui Paulo if (ap == NULL) 2139*f05cddf9SRui Paulo return; 2140*f05cddf9SRui Paulo ap->tries++; 2141*f05cddf9SRui Paulo os_get_time(&ap->last_attempt); 2142*f05cddf9SRui Paulo } 2143