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