xref: /freebsd/contrib/wpa/wpa_supplicant/wps_supplicant.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * wpa_supplicant / WPS integration
35b9c547cSRui Paulo  * Copyright (c) 2008-2014, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui 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"
14f05cddf9SRui 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"
22f05cddf9SRui Paulo #include "eapol_supp/eapol_supp_sm.h"
23e28a4053SRui Paulo #include "rsn_supp/wpa.h"
24f05cddf9SRui 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"
29c1d255d3SCy Schubert #include "bssid_ignore.h"
30e28a4053SRui Paulo #include "bss.h"
31e28a4053SRui Paulo #include "scan.h"
32f05cddf9SRui Paulo #include "ap.h"
33f05cddf9SRui Paulo #include "p2p/p2p.h"
34f05cddf9SRui Paulo #include "p2p_supplicant.h"
3539beb93cSSam Leffler #include "wps_supplicant.h"
3639beb93cSSam Leffler 
373157ba21SRui Paulo 
38f05cddf9SRui Paulo #ifndef WPS_PIN_SCAN_IGNORE_SEL_REG
3939beb93cSSam Leffler #define WPS_PIN_SCAN_IGNORE_SEL_REG 3
40f05cddf9SRui Paulo #endif /* WPS_PIN_SCAN_IGNORE_SEL_REG */
4139beb93cSSam Leffler 
42325151a3SRui Paulo /*
43325151a3SRui Paulo  * The minimum time in seconds before trying to associate to a WPS PIN AP that
44325151a3SRui Paulo  * does not have Selected Registrar TRUE.
45325151a3SRui Paulo  */
46325151a3SRui Paulo #ifndef WPS_PIN_TIME_IGNORE_SEL_REG
47325151a3SRui Paulo #define WPS_PIN_TIME_IGNORE_SEL_REG 5
48325151a3SRui Paulo #endif /* WPS_PIN_TIME_IGNORE_SEL_REG */
49325151a3SRui Paulo 
5039beb93cSSam Leffler static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
5139beb93cSSam Leffler static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
5239beb93cSSam Leffler 
5339beb93cSSam Leffler 
wpas_wps_clear_ap_info(struct wpa_supplicant * wpa_s)54f05cddf9SRui Paulo static void wpas_wps_clear_ap_info(struct wpa_supplicant *wpa_s)
55f05cddf9SRui Paulo {
56f05cddf9SRui Paulo 	os_free(wpa_s->wps_ap);
57f05cddf9SRui Paulo 	wpa_s->wps_ap = NULL;
58f05cddf9SRui Paulo 	wpa_s->num_wps_ap = 0;
59f05cddf9SRui Paulo 	wpa_s->wps_ap_iter = 0;
60f05cddf9SRui Paulo }
61f05cddf9SRui Paulo 
62f05cddf9SRui Paulo 
wpas_wps_assoc_with_cred(void * eloop_ctx,void * timeout_ctx)635b9c547cSRui Paulo static void wpas_wps_assoc_with_cred(void *eloop_ctx, void *timeout_ctx)
645b9c547cSRui Paulo {
655b9c547cSRui Paulo 	struct wpa_supplicant *wpa_s = eloop_ctx;
665b9c547cSRui Paulo 	int use_fast_assoc = timeout_ctx != NULL;
675b9c547cSRui Paulo 
685b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "WPS: Continuing association after eapol_cb");
695b9c547cSRui Paulo 	if (!use_fast_assoc ||
705b9c547cSRui Paulo 	    wpa_supplicant_fast_associate(wpa_s) != 1)
715b9c547cSRui Paulo 		wpa_supplicant_req_scan(wpa_s, 0, 0);
725b9c547cSRui Paulo }
735b9c547cSRui Paulo 
745b9c547cSRui Paulo 
wpas_wps_assoc_with_cred_cancel(struct wpa_supplicant * wpa_s)755b9c547cSRui Paulo static void wpas_wps_assoc_with_cred_cancel(struct wpa_supplicant *wpa_s)
765b9c547cSRui Paulo {
775b9c547cSRui Paulo 	eloop_cancel_timeout(wpas_wps_assoc_with_cred, wpa_s, (void *) 0);
785b9c547cSRui Paulo 	eloop_cancel_timeout(wpas_wps_assoc_with_cred, wpa_s, (void *) 1);
795b9c547cSRui Paulo }
805b9c547cSRui Paulo 
815b9c547cSRui Paulo 
wpas_wps_get_wps_ie(struct wpa_bss * bss)82*a90b9d01SCy Schubert static struct wpabuf * wpas_wps_get_wps_ie(struct wpa_bss *bss)
83*a90b9d01SCy Schubert {
84*a90b9d01SCy Schubert 	/* Return the latest receive WPS IE from the AP regardless of whether
85*a90b9d01SCy Schubert 	 * it was from a Beacon frame or Probe Response frame to avoid using
86*a90b9d01SCy Schubert 	 * stale information. */
87*a90b9d01SCy Schubert 	if (bss->beacon_newer)
88*a90b9d01SCy Schubert 		return wpa_bss_get_vendor_ie_multi_beacon(bss,
89*a90b9d01SCy Schubert 							  WPS_IE_VENDOR_TYPE);
90*a90b9d01SCy Schubert 	return wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
91*a90b9d01SCy Schubert }
92*a90b9d01SCy Schubert 
93*a90b9d01SCy Schubert 
wpas_wps_eapol_cb(struct wpa_supplicant * wpa_s)9439beb93cSSam Leffler int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
9539beb93cSSam Leffler {
965b9c547cSRui Paulo 	if (wpas_p2p_wps_eapol_cb(wpa_s) > 0)
975b9c547cSRui Paulo 		return 1;
985b9c547cSRui Paulo 
9939beb93cSSam Leffler 	if (!wpa_s->wps_success &&
10039beb93cSSam Leffler 	    wpa_s->current_ssid &&
10139beb93cSSam Leffler 	    eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
10239beb93cSSam Leffler 		const u8 *bssid = wpa_s->bssid;
10339beb93cSSam Leffler 		if (is_zero_ether_addr(bssid))
10439beb93cSSam Leffler 			bssid = wpa_s->pending_bssid;
10539beb93cSSam Leffler 
10639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: PIN registration with " MACSTR
10739beb93cSSam Leffler 			   " did not succeed - continue trying to find "
10839beb93cSSam Leffler 			   "suitable AP", MAC2STR(bssid));
109c1d255d3SCy Schubert 		wpa_bssid_ignore_add(wpa_s, bssid);
11039beb93cSSam Leffler 
11139beb93cSSam Leffler 		wpa_supplicant_deauthenticate(wpa_s,
11239beb93cSSam Leffler 					      WLAN_REASON_DEAUTH_LEAVING);
11339beb93cSSam Leffler 		wpa_s->reassociate = 1;
11439beb93cSSam Leffler 		wpa_supplicant_req_scan(wpa_s,
115c1d255d3SCy Schubert 					wpa_s->bssid_ignore_cleared ? 5 : 0, 0);
116c1d255d3SCy Schubert 		wpa_s->bssid_ignore_cleared = false;
11739beb93cSSam Leffler 		return 1;
11839beb93cSSam Leffler 	}
11939beb93cSSam Leffler 
120f05cddf9SRui Paulo 	wpas_wps_clear_ap_info(wpa_s);
12139beb93cSSam Leffler 	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
122f05cddf9SRui Paulo 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && !wpa_s->wps_success)
123f05cddf9SRui Paulo 		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL);
12439beb93cSSam Leffler 
12539beb93cSSam Leffler 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid &&
12639beb93cSSam Leffler 	    !(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
127f05cddf9SRui Paulo 		int disabled = wpa_s->current_ssid->disabled;
128f05cddf9SRui Paulo 		unsigned int freq = wpa_s->assoc_freq;
1295b9c547cSRui Paulo 		struct wpa_bss *bss;
1305b9c547cSRui Paulo 		struct wpa_ssid *ssid = NULL;
1315b9c547cSRui Paulo 		int use_fast_assoc = 0;
1325b9c547cSRui Paulo 
13339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
134f05cddf9SRui Paulo 			   "try to associate with the received credential "
135f05cddf9SRui Paulo 			   "(freq=%u)", freq);
1365b9c547cSRui Paulo 		wpa_s->own_disconnect_req = 1;
13739beb93cSSam Leffler 		wpa_supplicant_deauthenticate(wpa_s,
13839beb93cSSam Leffler 					      WLAN_REASON_DEAUTH_LEAVING);
139f05cddf9SRui Paulo 		if (disabled) {
140f05cddf9SRui Paulo 			wpa_printf(MSG_DEBUG, "WPS: Current network is "
141f05cddf9SRui Paulo 				   "disabled - wait for user to enable");
142f05cddf9SRui Paulo 			return 1;
143f05cddf9SRui Paulo 		}
144e28a4053SRui Paulo 		wpa_s->after_wps = 5;
145f05cddf9SRui Paulo 		wpa_s->wps_freq = freq;
146f05cddf9SRui Paulo 		wpa_s->normal_scans = 0;
14739beb93cSSam Leffler 		wpa_s->reassociate = 1;
1485b9c547cSRui Paulo 
1495b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Checking whether fast association "
1505b9c547cSRui Paulo 			   "without a new scan can be used");
1515b9c547cSRui Paulo 		bss = wpa_supplicant_pick_network(wpa_s, &ssid);
1525b9c547cSRui Paulo 		if (bss) {
1535b9c547cSRui Paulo 			struct wpabuf *wps;
1545b9c547cSRui Paulo 			struct wps_parse_attr attr;
1555b9c547cSRui Paulo 
156*a90b9d01SCy Schubert 			wps = wpas_wps_get_wps_ie(bss);
1575b9c547cSRui Paulo 			if (wps && wps_parse_msg(wps, &attr) == 0 &&
1585b9c547cSRui Paulo 			    attr.wps_state &&
1595b9c547cSRui Paulo 			    *attr.wps_state == WPS_STATE_CONFIGURED)
1605b9c547cSRui Paulo 				use_fast_assoc = 1;
1615b9c547cSRui Paulo 			wpabuf_free(wps);
1625b9c547cSRui Paulo 		}
1635b9c547cSRui Paulo 
1645b9c547cSRui Paulo 		/*
1655b9c547cSRui Paulo 		 * Complete the next step from an eloop timeout to allow pending
1665b9c547cSRui Paulo 		 * driver events related to the disconnection to be processed
1675b9c547cSRui Paulo 		 * first. This makes it less likely for disconnection event to
1685b9c547cSRui Paulo 		 * cause problems with the following connection.
1695b9c547cSRui Paulo 		 */
1705b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Continue association from timeout");
1715b9c547cSRui Paulo 		wpas_wps_assoc_with_cred_cancel(wpa_s);
1725b9c547cSRui Paulo 		eloop_register_timeout(0, 10000,
1735b9c547cSRui Paulo 				       wpas_wps_assoc_with_cred, wpa_s,
1745b9c547cSRui Paulo 				       use_fast_assoc ? (void *) 1 :
1755b9c547cSRui Paulo 				       (void *) 0);
17639beb93cSSam Leffler 		return 1;
17739beb93cSSam Leffler 	}
17839beb93cSSam Leffler 
17939beb93cSSam Leffler 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid) {
18039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting "
18139beb93cSSam Leffler 			   "for external credential processing");
18239beb93cSSam Leffler 		wpas_clear_wps(wpa_s);
1835b9c547cSRui Paulo 		wpa_s->own_disconnect_req = 1;
18439beb93cSSam Leffler 		wpa_supplicant_deauthenticate(wpa_s,
18539beb93cSSam Leffler 					      WLAN_REASON_DEAUTH_LEAVING);
18639beb93cSSam Leffler 		return 1;
18739beb93cSSam Leffler 	}
18839beb93cSSam Leffler 
18939beb93cSSam Leffler 	return 0;
19039beb93cSSam Leffler }
19139beb93cSSam Leffler 
19239beb93cSSam Leffler 
wpas_wps_security_workaround(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,const struct wps_credential * cred)1933157ba21SRui Paulo static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
1943157ba21SRui Paulo 					 struct wpa_ssid *ssid,
1953157ba21SRui Paulo 					 const struct wps_credential *cred)
1963157ba21SRui Paulo {
1973157ba21SRui Paulo 	struct wpa_driver_capa capa;
198e28a4053SRui Paulo 	struct wpa_bss *bss;
1993157ba21SRui Paulo 	const u8 *ie;
2003157ba21SRui Paulo 	struct wpa_ie_data adv;
2013157ba21SRui Paulo 	int wpa2 = 0, ccmp = 0;
202c1d255d3SCy Schubert 	enum wpa_driver_if_type iftype;
2033157ba21SRui Paulo 
2043157ba21SRui Paulo 	/*
2053157ba21SRui Paulo 	 * Many existing WPS APs do not know how to negotiate WPA2 or CCMP in
2063157ba21SRui Paulo 	 * case they are configured for mixed mode operation (WPA+WPA2 and
2073157ba21SRui Paulo 	 * TKIP+CCMP). Try to use scan results to figure out whether the AP
2083157ba21SRui Paulo 	 * actually supports stronger security and select that if the client
2093157ba21SRui Paulo 	 * has support for it, too.
2103157ba21SRui Paulo 	 */
2113157ba21SRui Paulo 
2123157ba21SRui Paulo 	if (wpa_drv_get_capa(wpa_s, &capa))
2133157ba21SRui Paulo 		return; /* Unknown what driver supports */
2143157ba21SRui Paulo 
215f05cddf9SRui Paulo 	if (ssid->ssid == NULL)
216f05cddf9SRui Paulo 		return;
217e28a4053SRui Paulo 	bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len);
21885732ac8SCy Schubert 	if (!bss)
21985732ac8SCy Schubert 		bss = wpa_bss_get(wpa_s, wpa_s->bssid,
22085732ac8SCy Schubert 				  ssid->ssid, ssid->ssid_len);
221e28a4053SRui Paulo 	if (bss == NULL) {
222e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS "
223e28a4053SRui Paulo 			   "table - use credential as-is");
2243157ba21SRui Paulo 		return;
2253157ba21SRui Paulo 	}
2263157ba21SRui Paulo 
227e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "WPS: AP found from BSS table");
228e28a4053SRui Paulo 
229e28a4053SRui Paulo 	ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
2303157ba21SRui Paulo 	if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0) {
2313157ba21SRui Paulo 		wpa2 = 1;
2323157ba21SRui Paulo 		if (adv.pairwise_cipher & WPA_CIPHER_CCMP)
2333157ba21SRui Paulo 			ccmp = 1;
2343157ba21SRui Paulo 	} else {
235e28a4053SRui Paulo 		ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
2363157ba21SRui Paulo 		if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0 &&
2373157ba21SRui Paulo 		    adv.pairwise_cipher & WPA_CIPHER_CCMP)
2383157ba21SRui Paulo 			ccmp = 1;
2393157ba21SRui Paulo 	}
2403157ba21SRui Paulo 
2413157ba21SRui Paulo 	if (ie == NULL && (ssid->proto & WPA_PROTO_WPA) &&
2423157ba21SRui Paulo 	    (ssid->pairwise_cipher & WPA_CIPHER_TKIP)) {
2433157ba21SRui Paulo 		/*
2443157ba21SRui Paulo 		 * TODO: This could be the initial AP configuration and the
2453157ba21SRui Paulo 		 * Beacon contents could change shortly. Should request a new
2463157ba21SRui Paulo 		 * scan and delay addition of the network until the updated
2473157ba21SRui Paulo 		 * scan results are available.
2483157ba21SRui Paulo 		 */
2493157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: The AP did not yet advertise WPA "
2503157ba21SRui Paulo 			   "support - use credential as-is");
2513157ba21SRui Paulo 		return;
2523157ba21SRui Paulo 	}
2533157ba21SRui Paulo 
254c1d255d3SCy Schubert 	iftype = ssid->p2p_group ? WPA_IF_P2P_CLIENT : WPA_IF_STATION;
255c1d255d3SCy Schubert 
2563157ba21SRui Paulo 	if (ccmp && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
2573157ba21SRui Paulo 	    (ssid->pairwise_cipher & WPA_CIPHER_TKIP) &&
258c1d255d3SCy Schubert 	    (capa.key_mgmt_iftype[iftype] &
259c1d255d3SCy Schubert 	     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2603157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Add CCMP into the credential "
2613157ba21SRui Paulo 			   "based on scan results");
2623157ba21SRui Paulo 		if (wpa_s->conf->ap_scan == 1)
2633157ba21SRui Paulo 			ssid->pairwise_cipher |= WPA_CIPHER_CCMP;
2643157ba21SRui Paulo 		else
2653157ba21SRui Paulo 			ssid->pairwise_cipher = WPA_CIPHER_CCMP;
2663157ba21SRui Paulo 	}
2673157ba21SRui Paulo 
2683157ba21SRui Paulo 	if (wpa2 && !(ssid->proto & WPA_PROTO_RSN) &&
2693157ba21SRui Paulo 	    (ssid->proto & WPA_PROTO_WPA) &&
2703157ba21SRui Paulo 	    (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP)) {
2713157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Add WPA2 into the credential "
2723157ba21SRui Paulo 			   "based on scan results");
2733157ba21SRui Paulo 		if (wpa_s->conf->ap_scan == 1)
2743157ba21SRui Paulo 			ssid->proto |= WPA_PROTO_RSN;
2753157ba21SRui Paulo 		else
2763157ba21SRui Paulo 			ssid->proto = WPA_PROTO_RSN;
2773157ba21SRui Paulo 	}
2783157ba21SRui Paulo }
2793157ba21SRui Paulo 
2803157ba21SRui Paulo 
wpas_wps_remove_dup_network(struct wpa_supplicant * wpa_s,struct wpa_ssid * new_ssid)2815b9c547cSRui Paulo static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s,
2825b9c547cSRui Paulo 					struct wpa_ssid *new_ssid)
2835b9c547cSRui Paulo {
2845b9c547cSRui Paulo 	struct wpa_ssid *ssid, *next;
2855b9c547cSRui Paulo 
2865b9c547cSRui Paulo 	for (ssid = wpa_s->conf->ssid, next = ssid ? ssid->next : NULL; ssid;
2875b9c547cSRui Paulo 	     ssid = next, next = ssid ? ssid->next : NULL) {
2885b9c547cSRui Paulo 		/*
2895b9c547cSRui Paulo 		 * new_ssid has already been added to the list in
2905b9c547cSRui Paulo 		 * wpas_wps_add_network(), so skip it.
2915b9c547cSRui Paulo 		 */
2925b9c547cSRui Paulo 		if (ssid == new_ssid)
2935b9c547cSRui Paulo 			continue;
2945b9c547cSRui Paulo 
2955b9c547cSRui Paulo 		if (ssid->bssid_set || new_ssid->bssid_set) {
2965b9c547cSRui Paulo 			if (ssid->bssid_set != new_ssid->bssid_set)
2975b9c547cSRui Paulo 				continue;
298*a90b9d01SCy Schubert 			if (!ether_addr_equal(ssid->bssid, new_ssid->bssid))
2995b9c547cSRui Paulo 				continue;
3005b9c547cSRui Paulo 		}
3015b9c547cSRui Paulo 
3025b9c547cSRui Paulo 		/* compare SSID */
3035b9c547cSRui Paulo 		if (ssid->ssid_len == 0 || ssid->ssid_len != new_ssid->ssid_len)
3045b9c547cSRui Paulo 			continue;
3055b9c547cSRui Paulo 
3065b9c547cSRui Paulo 		if (ssid->ssid && new_ssid->ssid) {
3075b9c547cSRui Paulo 			if (os_memcmp(ssid->ssid, new_ssid->ssid,
3085b9c547cSRui Paulo 				      ssid->ssid_len) != 0)
3095b9c547cSRui Paulo 				continue;
3105b9c547cSRui Paulo 		} else if (ssid->ssid || new_ssid->ssid)
3115b9c547cSRui Paulo 			continue;
3125b9c547cSRui Paulo 
3135b9c547cSRui Paulo 		/* compare security parameters */
3145b9c547cSRui Paulo 		if (ssid->auth_alg != new_ssid->auth_alg ||
3155b9c547cSRui Paulo 		    ssid->key_mgmt != new_ssid->key_mgmt ||
3165b9c547cSRui Paulo 		    (ssid->group_cipher != new_ssid->group_cipher &&
3175b9c547cSRui Paulo 		     !(ssid->group_cipher & new_ssid->group_cipher &
3185b9c547cSRui Paulo 		       WPA_CIPHER_CCMP)))
3195b9c547cSRui Paulo 			continue;
3205b9c547cSRui Paulo 
3215b9c547cSRui Paulo 		/*
3225b9c547cSRui Paulo 		 * Some existing WPS APs will send two creds in case they are
3235b9c547cSRui Paulo 		 * configured for mixed mode operation (WPA+WPA2 and TKIP+CCMP).
3245b9c547cSRui Paulo 		 * Try to merge these two creds if they are received in the same
3255b9c547cSRui Paulo 		 * M8 message.
3265b9c547cSRui Paulo 		 */
3275b9c547cSRui Paulo 		if (ssid->wps_run && ssid->wps_run == new_ssid->wps_run &&
3285b9c547cSRui Paulo 		    wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
3295b9c547cSRui Paulo 			if (new_ssid->passphrase && ssid->passphrase &&
3305b9c547cSRui Paulo 			    os_strcmp(new_ssid->passphrase, ssid->passphrase) !=
3315b9c547cSRui Paulo 			    0) {
3325b9c547cSRui Paulo 				wpa_printf(MSG_DEBUG,
3335b9c547cSRui Paulo 					   "WPS: M8 Creds with different passphrase - do not merge");
3345b9c547cSRui Paulo 				continue;
3355b9c547cSRui Paulo 			}
3365b9c547cSRui Paulo 
3375b9c547cSRui Paulo 			if (new_ssid->psk_set &&
3385b9c547cSRui Paulo 			    (!ssid->psk_set ||
3395b9c547cSRui Paulo 			     os_memcmp(new_ssid->psk, ssid->psk, 32) != 0)) {
3405b9c547cSRui Paulo 				wpa_printf(MSG_DEBUG,
3415b9c547cSRui Paulo 					   "WPS: M8 Creds with different PSK - do not merge");
3425b9c547cSRui Paulo 				continue;
3435b9c547cSRui Paulo 			}
3445b9c547cSRui Paulo 
3455b9c547cSRui Paulo 			if ((new_ssid->passphrase && !ssid->passphrase) ||
3465b9c547cSRui Paulo 			    (!new_ssid->passphrase && ssid->passphrase)) {
3475b9c547cSRui Paulo 				wpa_printf(MSG_DEBUG,
3485b9c547cSRui Paulo 					   "WPS: M8 Creds with different passphrase/PSK type - do not merge");
3495b9c547cSRui Paulo 				continue;
3505b9c547cSRui Paulo 			}
3515b9c547cSRui Paulo 
3525b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG,
3535b9c547cSRui Paulo 				   "WPS: Workaround - merge likely WPA/WPA2-mixed mode creds in same M8 message");
3545b9c547cSRui Paulo 			new_ssid->proto |= ssid->proto;
3555b9c547cSRui Paulo 			new_ssid->pairwise_cipher |= ssid->pairwise_cipher;
3565b9c547cSRui Paulo 		} else {
3575b9c547cSRui Paulo 			/*
3585b9c547cSRui Paulo 			 * proto and pairwise_cipher difference matter for
3595b9c547cSRui Paulo 			 * non-mixed-mode creds.
3605b9c547cSRui Paulo 			 */
3615b9c547cSRui Paulo 			if (ssid->proto != new_ssid->proto ||
3625b9c547cSRui Paulo 			    ssid->pairwise_cipher != new_ssid->pairwise_cipher)
3635b9c547cSRui Paulo 				continue;
3645b9c547cSRui Paulo 		}
3655b9c547cSRui Paulo 
3665b9c547cSRui Paulo 		/* Remove the duplicated older network entry. */
3675b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id);
3685b9c547cSRui Paulo 		wpas_notify_network_removed(wpa_s, ssid);
3695b9c547cSRui Paulo 		wpa_config_remove_network(wpa_s->conf, ssid->id);
3705b9c547cSRui Paulo 	}
3715b9c547cSRui Paulo }
3725b9c547cSRui Paulo 
3735b9c547cSRui Paulo 
wpa_supplicant_wps_cred(void * ctx,const struct wps_credential * cred)37439beb93cSSam Leffler static int wpa_supplicant_wps_cred(void *ctx,
37539beb93cSSam Leffler 				   const struct wps_credential *cred)
37639beb93cSSam Leffler {
37739beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
37839beb93cSSam Leffler 	struct wpa_ssid *ssid = wpa_s->current_ssid;
3793157ba21SRui Paulo 	u16 auth_type;
380f05cddf9SRui Paulo #ifdef CONFIG_WPS_REG_DISABLE_OPEN
381f05cddf9SRui Paulo 	int registrar = 0;
382f05cddf9SRui Paulo #endif /* CONFIG_WPS_REG_DISABLE_OPEN */
383c1d255d3SCy Schubert 	bool add_sae;
38439beb93cSSam Leffler 
38539beb93cSSam Leffler 	if ((wpa_s->conf->wps_cred_processing == 1 ||
38639beb93cSSam Leffler 	     wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) {
38739beb93cSSam Leffler 		size_t blen = cred->cred_attr_len * 2 + 1;
38839beb93cSSam Leffler 		char *buf = os_malloc(blen);
38939beb93cSSam Leffler 		if (buf) {
39039beb93cSSam Leffler 			wpa_snprintf_hex(buf, blen,
39139beb93cSSam Leffler 					 cred->cred_attr, cred->cred_attr_len);
39239beb93cSSam Leffler 			wpa_msg(wpa_s, MSG_INFO, "%s%s",
39339beb93cSSam Leffler 				WPS_EVENT_CRED_RECEIVED, buf);
39439beb93cSSam Leffler 			os_free(buf);
39539beb93cSSam Leffler 		}
396e28a4053SRui Paulo 
397e28a4053SRui Paulo 		wpas_notify_wps_credential(wpa_s, cred);
39839beb93cSSam Leffler 	} else
39939beb93cSSam Leffler 		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED);
40039beb93cSSam Leffler 
40139beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
40239beb93cSSam Leffler 			cred->cred_attr, cred->cred_attr_len);
40339beb93cSSam Leffler 
40439beb93cSSam Leffler 	if (wpa_s->conf->wps_cred_processing == 1)
40539beb93cSSam Leffler 		return 0;
40639beb93cSSam Leffler 
4073157ba21SRui Paulo 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
4083157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
40939beb93cSSam Leffler 		   cred->auth_type);
4103157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
4113157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
4123157ba21SRui Paulo 	wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
4133157ba21SRui Paulo 			cred->key, cred->key_len);
4143157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
4153157ba21SRui Paulo 		   MAC2STR(cred->mac_addr));
4163157ba21SRui Paulo 
4173157ba21SRui Paulo 	auth_type = cred->auth_type;
4183157ba21SRui Paulo 	if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
4193157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Workaround - convert mixed-mode "
4203157ba21SRui Paulo 			   "auth_type into WPA2PSK");
4213157ba21SRui Paulo 		auth_type = WPS_AUTH_WPA2PSK;
4223157ba21SRui Paulo 	}
4233157ba21SRui Paulo 
4243157ba21SRui Paulo 	if (auth_type != WPS_AUTH_OPEN &&
4253157ba21SRui Paulo 	    auth_type != WPS_AUTH_WPAPSK &&
4263157ba21SRui Paulo 	    auth_type != WPS_AUTH_WPA2PSK) {
4273157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
4283157ba21SRui Paulo 			   "unsupported authentication type 0x%x",
4293157ba21SRui Paulo 			   auth_type);
43039beb93cSSam Leffler 		return 0;
43139beb93cSSam Leffler 	}
43239beb93cSSam Leffler 
433f05cddf9SRui Paulo 	if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) {
434f05cddf9SRui Paulo 		if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) {
435f05cddf9SRui Paulo 			wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with "
436f05cddf9SRui Paulo 				   "invalid Network Key length %lu",
437f05cddf9SRui Paulo 				   (unsigned long) cred->key_len);
438f05cddf9SRui Paulo 			return -1;
439f05cddf9SRui Paulo 		}
440f05cddf9SRui Paulo 	}
441f05cddf9SRui Paulo 
44239beb93cSSam Leffler 	if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
44339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
44439beb93cSSam Leffler 			   "on the received credential");
445f05cddf9SRui Paulo #ifdef CONFIG_WPS_REG_DISABLE_OPEN
446f05cddf9SRui Paulo 		if (ssid->eap.identity &&
447f05cddf9SRui Paulo 		    ssid->eap.identity_len == WSC_ID_REGISTRAR_LEN &&
448f05cddf9SRui Paulo 		    os_memcmp(ssid->eap.identity, WSC_ID_REGISTRAR,
449f05cddf9SRui Paulo 			      WSC_ID_REGISTRAR_LEN) == 0)
450f05cddf9SRui Paulo 			registrar = 1;
451f05cddf9SRui Paulo #endif /* CONFIG_WPS_REG_DISABLE_OPEN */
45239beb93cSSam Leffler 		os_free(ssid->eap.identity);
45339beb93cSSam Leffler 		ssid->eap.identity = NULL;
45439beb93cSSam Leffler 		ssid->eap.identity_len = 0;
45539beb93cSSam Leffler 		os_free(ssid->eap.phase1);
45639beb93cSSam Leffler 		ssid->eap.phase1 = NULL;
45739beb93cSSam Leffler 		os_free(ssid->eap.eap_methods);
45839beb93cSSam Leffler 		ssid->eap.eap_methods = NULL;
459f05cddf9SRui Paulo 		if (!ssid->p2p_group) {
460f05cddf9SRui Paulo 			ssid->temporary = 0;
461f05cddf9SRui Paulo 			ssid->bssid_set = 0;
462f05cddf9SRui Paulo 		}
463f05cddf9SRui Paulo 		ssid->disabled_until.sec = 0;
464f05cddf9SRui Paulo 		ssid->disabled_until.usec = 0;
465f05cddf9SRui Paulo 		ssid->auth_failures = 0;
46639beb93cSSam Leffler 	} else {
46739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
46839beb93cSSam Leffler 			   "received credential");
46939beb93cSSam Leffler 		ssid = wpa_config_add_network(wpa_s->conf);
47039beb93cSSam Leffler 		if (ssid == NULL)
47139beb93cSSam Leffler 			return -1;
4725b9c547cSRui Paulo 		if (wpa_s->current_ssid) {
4735b9c547cSRui Paulo 			/*
4745b9c547cSRui Paulo 			 * Should the GO issue multiple credentials for some
4755b9c547cSRui Paulo 			 * reason, each credential should be marked as a
4765b9c547cSRui Paulo 			 * temporary P2P group similarly to the one that gets
4775b9c547cSRui Paulo 			 * marked as such based on the pre-configured values
4785b9c547cSRui Paulo 			 * used for the WPS network block.
4795b9c547cSRui Paulo 			 */
4805b9c547cSRui Paulo 			ssid->p2p_group = wpa_s->current_ssid->p2p_group;
4815b9c547cSRui Paulo 			ssid->temporary = wpa_s->current_ssid->temporary;
4825b9c547cSRui Paulo 		}
483e28a4053SRui Paulo 		wpas_notify_network_added(wpa_s, ssid);
48439beb93cSSam Leffler 	}
48539beb93cSSam Leffler 
48639beb93cSSam Leffler 	wpa_config_set_network_defaults(ssid);
4875b9c547cSRui Paulo 	ssid->wps_run = wpa_s->wps_run;
48839beb93cSSam Leffler 
48939beb93cSSam Leffler 	os_free(ssid->ssid);
49039beb93cSSam Leffler 	ssid->ssid = os_malloc(cred->ssid_len);
49139beb93cSSam Leffler 	if (ssid->ssid) {
49239beb93cSSam Leffler 		os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len);
49339beb93cSSam Leffler 		ssid->ssid_len = cred->ssid_len;
49439beb93cSSam Leffler 	}
49539beb93cSSam Leffler 
49639beb93cSSam Leffler 	switch (cred->encr_type) {
49739beb93cSSam Leffler 	case WPS_ENCR_NONE:
49839beb93cSSam Leffler 		break;
49939beb93cSSam Leffler 	case WPS_ENCR_TKIP:
500c1d255d3SCy Schubert 		ssid->pairwise_cipher = WPA_CIPHER_TKIP | WPA_CIPHER_CCMP;
50139beb93cSSam Leffler 		break;
50239beb93cSSam Leffler 	case WPS_ENCR_AES:
50339beb93cSSam Leffler 		ssid->pairwise_cipher = WPA_CIPHER_CCMP;
5045b9c547cSRui Paulo 		if (wpa_s->drv_capa_known &&
5055b9c547cSRui Paulo 		    (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP)) {
5065b9c547cSRui Paulo 			ssid->pairwise_cipher |= WPA_CIPHER_GCMP;
5075b9c547cSRui Paulo 			ssid->group_cipher |= WPA_CIPHER_GCMP;
5085b9c547cSRui Paulo 		}
50985732ac8SCy Schubert 		if (wpa_s->drv_capa_known &&
51085732ac8SCy Schubert 		    (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP_256)) {
51185732ac8SCy Schubert 			ssid->pairwise_cipher |= WPA_CIPHER_GCMP_256;
51285732ac8SCy Schubert 			ssid->group_cipher |= WPA_CIPHER_GCMP_256;
51385732ac8SCy Schubert 		}
51485732ac8SCy Schubert 		if (wpa_s->drv_capa_known &&
51585732ac8SCy Schubert 		    (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_CCMP_256)) {
51685732ac8SCy Schubert 			ssid->pairwise_cipher |= WPA_CIPHER_CCMP_256;
51785732ac8SCy Schubert 			ssid->group_cipher |= WPA_CIPHER_CCMP_256;
51885732ac8SCy Schubert 		}
51939beb93cSSam Leffler 		break;
52039beb93cSSam Leffler 	}
52139beb93cSSam Leffler 
5223157ba21SRui Paulo 	switch (auth_type) {
52339beb93cSSam Leffler 	case WPS_AUTH_OPEN:
52439beb93cSSam Leffler 		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
52539beb93cSSam Leffler 		ssid->key_mgmt = WPA_KEY_MGMT_NONE;
52639beb93cSSam Leffler 		ssid->proto = 0;
527f05cddf9SRui Paulo #ifdef CONFIG_WPS_REG_DISABLE_OPEN
528f05cddf9SRui Paulo 		if (registrar) {
529f05cddf9SRui Paulo 			wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OPEN_NETWORK
530f05cddf9SRui Paulo 				"id=%d - Credentials for an open "
531f05cddf9SRui Paulo 				"network disabled by default - use "
532f05cddf9SRui Paulo 				"'select_network %d' to enable",
533f05cddf9SRui Paulo 				ssid->id, ssid->id);
534f05cddf9SRui Paulo 			ssid->disabled = 1;
535f05cddf9SRui Paulo 		}
536f05cddf9SRui Paulo #endif /* CONFIG_WPS_REG_DISABLE_OPEN */
53739beb93cSSam Leffler 		break;
53839beb93cSSam Leffler 	case WPS_AUTH_WPAPSK:
53939beb93cSSam Leffler 		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
54039beb93cSSam Leffler 		ssid->key_mgmt = WPA_KEY_MGMT_PSK;
541c1d255d3SCy Schubert 		ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
54239beb93cSSam Leffler 		break;
54339beb93cSSam Leffler 	case WPS_AUTH_WPA2PSK:
54439beb93cSSam Leffler 		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
54539beb93cSSam Leffler 		ssid->key_mgmt = WPA_KEY_MGMT_PSK;
546c1d255d3SCy Schubert 		add_sae = wpa_s->conf->wps_cred_add_sae;
547c1d255d3SCy Schubert #ifdef CONFIG_P2P
548c1d255d3SCy Schubert 		if (ssid->p2p_group && is_p2p_6ghz_capable(wpa_s->global->p2p))
549c1d255d3SCy Schubert 			add_sae = true;
550c1d255d3SCy Schubert #endif /* CONFIG_P2P */
551c1d255d3SCy Schubert 		if (add_sae && cred->key_len != 2 * PMK_LEN) {
552c1d255d3SCy Schubert 			ssid->auth_alg = 0;
5534bc52338SCy Schubert 			ssid->key_mgmt |= WPA_KEY_MGMT_SAE;
5544bc52338SCy Schubert 			ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
5554bc52338SCy Schubert 		}
55639beb93cSSam Leffler 		ssid->proto = WPA_PROTO_RSN;
55739beb93cSSam Leffler 		break;
55839beb93cSSam Leffler 	}
55939beb93cSSam Leffler 
5604bc52338SCy Schubert 	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
56139beb93cSSam Leffler 		if (cred->key_len == 2 * PMK_LEN) {
56239beb93cSSam Leffler 			if (hexstr2bin((const char *) cred->key, ssid->psk,
56339beb93cSSam Leffler 				       PMK_LEN)) {
56439beb93cSSam Leffler 				wpa_printf(MSG_ERROR, "WPS: Invalid Network "
56539beb93cSSam Leffler 					   "Key");
56639beb93cSSam Leffler 				return -1;
56739beb93cSSam Leffler 			}
56839beb93cSSam Leffler 			ssid->psk_set = 1;
569f05cddf9SRui Paulo 			ssid->export_keys = 1;
57039beb93cSSam Leffler 		} else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) {
57139beb93cSSam Leffler 			os_free(ssid->passphrase);
57239beb93cSSam Leffler 			ssid->passphrase = os_malloc(cred->key_len + 1);
57339beb93cSSam Leffler 			if (ssid->passphrase == NULL)
57439beb93cSSam Leffler 				return -1;
57539beb93cSSam Leffler 			os_memcpy(ssid->passphrase, cred->key, cred->key_len);
57639beb93cSSam Leffler 			ssid->passphrase[cred->key_len] = '\0';
57739beb93cSSam Leffler 			wpa_config_update_psk(ssid);
578f05cddf9SRui Paulo 			ssid->export_keys = 1;
57939beb93cSSam Leffler 		} else {
58039beb93cSSam Leffler 			wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
58139beb93cSSam Leffler 				   "length %lu",
58239beb93cSSam Leffler 				   (unsigned long) cred->key_len);
58339beb93cSSam Leffler 			return -1;
58439beb93cSSam Leffler 		}
58539beb93cSSam Leffler 	}
586325151a3SRui Paulo 	ssid->priority = wpa_s->conf->wps_priority;
58739beb93cSSam Leffler 
5883157ba21SRui Paulo 	wpas_wps_security_workaround(wpa_s, ssid, cred);
5893157ba21SRui Paulo 
5905b9c547cSRui Paulo 	wpas_wps_remove_dup_network(wpa_s, ssid);
591f05cddf9SRui Paulo 
59239beb93cSSam Leffler #ifndef CONFIG_NO_CONFIG_WRITE
59339beb93cSSam Leffler 	if (wpa_s->conf->update_config &&
59439beb93cSSam Leffler 	    wpa_config_write(wpa_s->confname, wpa_s->conf)) {
59539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration");
59639beb93cSSam Leffler 		return -1;
59739beb93cSSam Leffler 	}
59839beb93cSSam Leffler #endif /* CONFIG_NO_CONFIG_WRITE */
59939beb93cSSam Leffler 
600325151a3SRui Paulo 	if (ssid->priority)
601325151a3SRui Paulo 		wpa_config_update_prio_list(wpa_s->conf);
602325151a3SRui Paulo 
603f05cddf9SRui Paulo 	/*
604f05cddf9SRui Paulo 	 * Optimize the post-WPS scan based on the channel used during
605f05cddf9SRui Paulo 	 * the provisioning in case EAP-Failure is not received.
606f05cddf9SRui Paulo 	 */
607f05cddf9SRui Paulo 	wpa_s->after_wps = 5;
608f05cddf9SRui Paulo 	wpa_s->wps_freq = wpa_s->assoc_freq;
609f05cddf9SRui Paulo 
61039beb93cSSam Leffler 	return 0;
61139beb93cSSam Leffler }
61239beb93cSSam Leffler 
61339beb93cSSam Leffler 
wpa_supplicant_wps_event_m2d(struct wpa_supplicant * wpa_s,struct wps_event_m2d * m2d)61439beb93cSSam Leffler static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
61539beb93cSSam Leffler 					 struct wps_event_m2d *m2d)
61639beb93cSSam Leffler {
61739beb93cSSam Leffler 	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_M2D
61839beb93cSSam Leffler 		"dev_password_id=%d config_error=%d",
61939beb93cSSam Leffler 		m2d->dev_password_id, m2d->config_error);
620e28a4053SRui Paulo 	wpas_notify_wps_event_m2d(wpa_s, m2d);
621f05cddf9SRui Paulo #ifdef CONFIG_P2P
622780fb4a2SCy Schubert 	if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s) {
623780fb4a2SCy Schubert 		wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_M2D
624f05cddf9SRui Paulo 			"dev_password_id=%d config_error=%d",
625f05cddf9SRui Paulo 			m2d->dev_password_id, m2d->config_error);
626f05cddf9SRui Paulo 	}
627f05cddf9SRui Paulo 	if (m2d->config_error == WPS_CFG_MULTIPLE_PBC_DETECTED) {
628f05cddf9SRui Paulo 		/*
629f05cddf9SRui Paulo 		 * Notify P2P from eloop timeout to avoid issues with the
630f05cddf9SRui Paulo 		 * interface getting removed while processing a message.
631f05cddf9SRui Paulo 		 */
6325b9c547cSRui Paulo 		eloop_register_timeout(0, 0, wpas_p2p_pbc_overlap_cb, wpa_s,
633f05cddf9SRui Paulo 				       NULL);
634f05cddf9SRui Paulo 	}
635f05cddf9SRui Paulo #endif /* CONFIG_P2P */
63639beb93cSSam Leffler }
63739beb93cSSam Leffler 
63839beb93cSSam Leffler 
wpas_wps_clear_timeout(void * eloop_ctx,void * timeout_ctx)6395b9c547cSRui Paulo static void wpas_wps_clear_timeout(void *eloop_ctx, void *timeout_ctx)
6405b9c547cSRui Paulo {
6415b9c547cSRui Paulo 	struct wpa_supplicant *wpa_s = eloop_ctx;
6425b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "WPS: Clear WPS network from timeout");
6435b9c547cSRui Paulo 	wpas_clear_wps(wpa_s);
6445b9c547cSRui Paulo }
6455b9c547cSRui Paulo 
646f05cddf9SRui Paulo 
wpa_supplicant_wps_event_fail(struct wpa_supplicant * wpa_s,struct wps_event_fail * fail)64739beb93cSSam Leffler static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
64839beb93cSSam Leffler 					  struct wps_event_fail *fail)
64939beb93cSSam Leffler {
650f05cddf9SRui Paulo 	if (fail->error_indication > 0 &&
651f05cddf9SRui Paulo 	    fail->error_indication < NUM_WPS_EI_VALUES) {
652f05cddf9SRui Paulo 		wpa_msg(wpa_s, MSG_INFO,
653f05cddf9SRui Paulo 			WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
654f05cddf9SRui Paulo 			fail->msg, fail->config_error, fail->error_indication,
6555b9c547cSRui Paulo 			wps_ei_str(fail->error_indication));
656780fb4a2SCy Schubert 		if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s)
657780fb4a2SCy Schubert 			wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
658f05cddf9SRui Paulo 				"msg=%d config_error=%d reason=%d (%s)",
659f05cddf9SRui Paulo 				fail->msg, fail->config_error,
660f05cddf9SRui Paulo 				fail->error_indication,
6615b9c547cSRui Paulo 				wps_ei_str(fail->error_indication));
662f05cddf9SRui Paulo 	} else {
663f05cddf9SRui Paulo 		wpa_msg(wpa_s, MSG_INFO,
664f05cddf9SRui Paulo 			WPS_EVENT_FAIL "msg=%d config_error=%d",
665f05cddf9SRui Paulo 			fail->msg, fail->config_error);
666780fb4a2SCy Schubert 		if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s)
667780fb4a2SCy Schubert 			wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
668f05cddf9SRui Paulo 				"msg=%d config_error=%d",
669f05cddf9SRui Paulo 				fail->msg, fail->config_error);
670f05cddf9SRui Paulo 	}
6715b9c547cSRui Paulo 
6725b9c547cSRui Paulo 	/*
6735b9c547cSRui Paulo 	 * Need to allow WPS processing to complete, e.g., by sending WSC_NACK.
6745b9c547cSRui Paulo 	 */
6755b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "WPS: Register timeout to clear WPS network");
6765b9c547cSRui Paulo 	eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
6775b9c547cSRui Paulo 	eloop_register_timeout(0, 100000, wpas_wps_clear_timeout, wpa_s, NULL);
6785b9c547cSRui Paulo 
679e28a4053SRui Paulo 	wpas_notify_wps_event_fail(wpa_s, fail);
680f05cddf9SRui Paulo 	wpas_p2p_wps_failed(wpa_s, fail);
681f05cddf9SRui Paulo }
682f05cddf9SRui Paulo 
683f05cddf9SRui Paulo 
684f05cddf9SRui Paulo static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx);
685f05cddf9SRui Paulo 
wpas_wps_reenable_networks(struct wpa_supplicant * wpa_s)686f05cddf9SRui Paulo static void wpas_wps_reenable_networks(struct wpa_supplicant *wpa_s)
687f05cddf9SRui Paulo {
688f05cddf9SRui Paulo 	struct wpa_ssid *ssid;
689f05cddf9SRui Paulo 	int changed = 0;
690f05cddf9SRui Paulo 
691f05cddf9SRui Paulo 	eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
692f05cddf9SRui Paulo 
693f05cddf9SRui Paulo 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
694f05cddf9SRui Paulo 		if (ssid->disabled_for_connect && ssid->disabled) {
695f05cddf9SRui Paulo 			ssid->disabled_for_connect = 0;
696f05cddf9SRui Paulo 			ssid->disabled = 0;
697f05cddf9SRui Paulo 			wpas_notify_network_enabled_changed(wpa_s, ssid);
698f05cddf9SRui Paulo 			changed++;
699f05cddf9SRui Paulo 		}
700f05cddf9SRui Paulo 	}
701f05cddf9SRui Paulo 
702f05cddf9SRui Paulo 	if (changed) {
703f05cddf9SRui Paulo #ifndef CONFIG_NO_CONFIG_WRITE
704f05cddf9SRui Paulo 		if (wpa_s->conf->update_config &&
705f05cddf9SRui Paulo 		    wpa_config_write(wpa_s->confname, wpa_s->conf)) {
706f05cddf9SRui Paulo 			wpa_printf(MSG_DEBUG, "WPS: Failed to update "
707f05cddf9SRui Paulo 				   "configuration");
708f05cddf9SRui Paulo 		}
709f05cddf9SRui Paulo #endif /* CONFIG_NO_CONFIG_WRITE */
710f05cddf9SRui Paulo 	}
711f05cddf9SRui Paulo }
712f05cddf9SRui Paulo 
713f05cddf9SRui Paulo 
wpas_wps_reenable_networks_cb(void * eloop_ctx,void * timeout_ctx)714f05cddf9SRui Paulo static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx)
715f05cddf9SRui Paulo {
716f05cddf9SRui Paulo 	struct wpa_supplicant *wpa_s = eloop_ctx;
717f05cddf9SRui Paulo 	/* Enable the networks disabled during wpas_wps_reassoc */
718f05cddf9SRui Paulo 	wpas_wps_reenable_networks(wpa_s);
71939beb93cSSam Leffler }
72039beb93cSSam Leffler 
72139beb93cSSam Leffler 
wpas_wps_reenable_networks_pending(struct wpa_supplicant * wpa_s)722780fb4a2SCy Schubert int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s)
723780fb4a2SCy Schubert {
724780fb4a2SCy Schubert 	return eloop_is_timeout_registered(wpas_wps_reenable_networks_cb,
725780fb4a2SCy Schubert 					   wpa_s, NULL);
726780fb4a2SCy Schubert }
727780fb4a2SCy Schubert 
728780fb4a2SCy Schubert 
wpa_supplicant_wps_event_success(struct wpa_supplicant * wpa_s)72939beb93cSSam Leffler static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
73039beb93cSSam Leffler {
73139beb93cSSam Leffler 	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
73239beb93cSSam Leffler 	wpa_s->wps_success = 1;
733e28a4053SRui Paulo 	wpas_notify_wps_event_success(wpa_s);
7345b9c547cSRui Paulo 	if (wpa_s->current_ssid)
7355b9c547cSRui Paulo 		wpas_clear_temp_disabled(wpa_s, wpa_s->current_ssid, 1);
736c1d255d3SCy Schubert 	wpa_s->consecutive_conn_failures = 0;
737f05cddf9SRui Paulo 
738f05cddf9SRui Paulo 	/*
739f05cddf9SRui Paulo 	 * Enable the networks disabled during wpas_wps_reassoc after 10
740f05cddf9SRui Paulo 	 * seconds. The 10 seconds timer is to allow the data connection to be
741f05cddf9SRui Paulo 	 * formed before allowing other networks to be selected.
742f05cddf9SRui Paulo 	 */
743f05cddf9SRui Paulo 	eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
744f05cddf9SRui Paulo 			       NULL);
745f05cddf9SRui Paulo 
746f05cddf9SRui Paulo 	wpas_p2p_wps_success(wpa_s, wpa_s->bssid, 0);
747e28a4053SRui Paulo }
748e28a4053SRui Paulo 
749e28a4053SRui Paulo 
wpa_supplicant_wps_event_er_ap_add(struct wpa_supplicant * wpa_s,struct wps_event_er_ap * ap)750e28a4053SRui Paulo static void wpa_supplicant_wps_event_er_ap_add(struct wpa_supplicant *wpa_s,
751e28a4053SRui Paulo 					       struct wps_event_er_ap *ap)
752e28a4053SRui Paulo {
753e28a4053SRui Paulo 	char uuid_str[100];
754e28a4053SRui Paulo 	char dev_type[WPS_DEV_TYPE_BUFSIZE];
755e28a4053SRui Paulo 
756e28a4053SRui Paulo 	uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str));
757e28a4053SRui Paulo 	if (ap->pri_dev_type)
758e28a4053SRui Paulo 		wps_dev_type_bin2str(ap->pri_dev_type, dev_type,
759e28a4053SRui Paulo 				     sizeof(dev_type));
760e28a4053SRui Paulo 	else
761e28a4053SRui Paulo 		dev_type[0] = '\0';
762e28a4053SRui Paulo 
763e28a4053SRui Paulo 	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_ADD "%s " MACSTR
764e28a4053SRui Paulo 		" pri_dev_type=%s wps_state=%d |%s|%s|%s|%s|%s|%s|",
765e28a4053SRui Paulo 		uuid_str, MAC2STR(ap->mac_addr), dev_type, ap->wps_state,
766e28a4053SRui Paulo 		ap->friendly_name ? ap->friendly_name : "",
767e28a4053SRui Paulo 		ap->manufacturer ? ap->manufacturer : "",
768e28a4053SRui Paulo 		ap->model_description ? ap->model_description : "",
769e28a4053SRui Paulo 		ap->model_name ? ap->model_name : "",
770e28a4053SRui Paulo 		ap->manufacturer_url ? ap->manufacturer_url : "",
771e28a4053SRui Paulo 		ap->model_url ? ap->model_url : "");
772e28a4053SRui Paulo }
773e28a4053SRui Paulo 
774e28a4053SRui Paulo 
wpa_supplicant_wps_event_er_ap_remove(struct wpa_supplicant * wpa_s,struct wps_event_er_ap * ap)775e28a4053SRui Paulo static void wpa_supplicant_wps_event_er_ap_remove(struct wpa_supplicant *wpa_s,
776e28a4053SRui Paulo 						  struct wps_event_er_ap *ap)
777e28a4053SRui Paulo {
778e28a4053SRui Paulo 	char uuid_str[100];
779e28a4053SRui Paulo 	uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str));
780e28a4053SRui Paulo 	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_REMOVE "%s", uuid_str);
781e28a4053SRui Paulo }
782e28a4053SRui Paulo 
783e28a4053SRui Paulo 
wpa_supplicant_wps_event_er_enrollee_add(struct wpa_supplicant * wpa_s,struct wps_event_er_enrollee * enrollee)784e28a4053SRui Paulo static void wpa_supplicant_wps_event_er_enrollee_add(
785e28a4053SRui Paulo 	struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee)
786e28a4053SRui Paulo {
787e28a4053SRui Paulo 	char uuid_str[100];
788e28a4053SRui Paulo 	char dev_type[WPS_DEV_TYPE_BUFSIZE];
789e28a4053SRui Paulo 
790e28a4053SRui Paulo 	uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str));
791e28a4053SRui Paulo 	if (enrollee->pri_dev_type)
792e28a4053SRui Paulo 		wps_dev_type_bin2str(enrollee->pri_dev_type, dev_type,
793e28a4053SRui Paulo 				     sizeof(dev_type));
794e28a4053SRui Paulo 	else
795e28a4053SRui Paulo 		dev_type[0] = '\0';
796e28a4053SRui Paulo 
797e28a4053SRui Paulo 	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_ADD "%s " MACSTR
798e28a4053SRui Paulo 		" M1=%d config_methods=0x%x dev_passwd_id=%d pri_dev_type=%s "
799e28a4053SRui Paulo 		"|%s|%s|%s|%s|%s|",
800e28a4053SRui Paulo 		uuid_str, MAC2STR(enrollee->mac_addr), enrollee->m1_received,
801e28a4053SRui Paulo 		enrollee->config_methods, enrollee->dev_passwd_id, dev_type,
802e28a4053SRui Paulo 		enrollee->dev_name ? enrollee->dev_name : "",
803e28a4053SRui Paulo 		enrollee->manufacturer ? enrollee->manufacturer : "",
804e28a4053SRui Paulo 		enrollee->model_name ? enrollee->model_name : "",
805e28a4053SRui Paulo 		enrollee->model_number ? enrollee->model_number : "",
806e28a4053SRui Paulo 		enrollee->serial_number ? enrollee->serial_number : "");
807e28a4053SRui Paulo }
808e28a4053SRui Paulo 
809e28a4053SRui Paulo 
wpa_supplicant_wps_event_er_enrollee_remove(struct wpa_supplicant * wpa_s,struct wps_event_er_enrollee * enrollee)810e28a4053SRui Paulo static void wpa_supplicant_wps_event_er_enrollee_remove(
811e28a4053SRui Paulo 	struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee)
812e28a4053SRui Paulo {
813e28a4053SRui Paulo 	char uuid_str[100];
814e28a4053SRui Paulo 	uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str));
815e28a4053SRui Paulo 	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_REMOVE "%s " MACSTR,
816e28a4053SRui Paulo 		uuid_str, MAC2STR(enrollee->mac_addr));
81739beb93cSSam Leffler }
81839beb93cSSam Leffler 
81939beb93cSSam Leffler 
wpa_supplicant_wps_event_er_ap_settings(struct wpa_supplicant * wpa_s,struct wps_event_er_ap_settings * ap_settings)820f05cddf9SRui Paulo static void wpa_supplicant_wps_event_er_ap_settings(
821f05cddf9SRui Paulo 	struct wpa_supplicant *wpa_s,
822f05cddf9SRui Paulo 	struct wps_event_er_ap_settings *ap_settings)
823f05cddf9SRui Paulo {
824f05cddf9SRui Paulo 	char uuid_str[100];
825f05cddf9SRui Paulo 	char key_str[65];
826f05cddf9SRui Paulo 	const struct wps_credential *cred = ap_settings->cred;
827f05cddf9SRui Paulo 
828f05cddf9SRui Paulo 	key_str[0] = '\0';
829f05cddf9SRui Paulo 	if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
830f05cddf9SRui Paulo 		if (cred->key_len >= 8 && cred->key_len <= 64) {
831f05cddf9SRui Paulo 			os_memcpy(key_str, cred->key, cred->key_len);
832f05cddf9SRui Paulo 			key_str[cred->key_len] = '\0';
833f05cddf9SRui Paulo 		}
834f05cddf9SRui Paulo 	}
835f05cddf9SRui Paulo 
836f05cddf9SRui Paulo 	uuid_bin2str(ap_settings->uuid, uuid_str, sizeof(uuid_str));
837f05cddf9SRui Paulo 	/* Use wpa_msg_ctrl to avoid showing the key in debug log */
838f05cddf9SRui Paulo 	wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_SETTINGS
839f05cddf9SRui Paulo 		     "uuid=%s ssid=%s auth_type=0x%04x encr_type=0x%04x "
840f05cddf9SRui Paulo 		     "key=%s",
841f05cddf9SRui Paulo 		     uuid_str, wpa_ssid_txt(cred->ssid, cred->ssid_len),
842f05cddf9SRui Paulo 		     cred->auth_type, cred->encr_type, key_str);
843f05cddf9SRui Paulo }
844f05cddf9SRui Paulo 
845f05cddf9SRui Paulo 
wpa_supplicant_wps_event_er_set_sel_reg(struct wpa_supplicant * wpa_s,struct wps_event_er_set_selected_registrar * ev)846f05cddf9SRui Paulo static void wpa_supplicant_wps_event_er_set_sel_reg(
847f05cddf9SRui Paulo 	struct wpa_supplicant *wpa_s,
848f05cddf9SRui Paulo 	struct wps_event_er_set_selected_registrar *ev)
849f05cddf9SRui Paulo {
850f05cddf9SRui Paulo 	char uuid_str[100];
851f05cddf9SRui Paulo 
852f05cddf9SRui Paulo 	uuid_bin2str(ev->uuid, uuid_str, sizeof(uuid_str));
853f05cddf9SRui Paulo 	switch (ev->state) {
854f05cddf9SRui Paulo 	case WPS_ER_SET_SEL_REG_START:
855f05cddf9SRui Paulo 		wpa_msg(wpa_s, MSG_DEBUG, WPS_EVENT_ER_SET_SEL_REG
856f05cddf9SRui Paulo 			"uuid=%s state=START sel_reg=%d dev_passwd_id=%u "
857f05cddf9SRui Paulo 			"sel_reg_config_methods=0x%x",
858f05cddf9SRui Paulo 			uuid_str, ev->sel_reg, ev->dev_passwd_id,
859f05cddf9SRui Paulo 			ev->sel_reg_config_methods);
860f05cddf9SRui Paulo 		break;
861f05cddf9SRui Paulo 	case WPS_ER_SET_SEL_REG_DONE:
862f05cddf9SRui Paulo 		wpa_msg(wpa_s, MSG_DEBUG, WPS_EVENT_ER_SET_SEL_REG
863f05cddf9SRui Paulo 			"uuid=%s state=DONE", uuid_str);
864f05cddf9SRui Paulo 		break;
865f05cddf9SRui Paulo 	case WPS_ER_SET_SEL_REG_FAILED:
866f05cddf9SRui Paulo 		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_SET_SEL_REG
867f05cddf9SRui Paulo 			"uuid=%s state=FAILED", uuid_str);
868f05cddf9SRui Paulo 		break;
869f05cddf9SRui Paulo 	}
870f05cddf9SRui Paulo }
871f05cddf9SRui Paulo 
872f05cddf9SRui Paulo 
wpa_supplicant_wps_event(void * ctx,enum wps_event event,union wps_event_data * data)87339beb93cSSam Leffler static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
87439beb93cSSam Leffler 				     union wps_event_data *data)
87539beb93cSSam Leffler {
87639beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
87739beb93cSSam Leffler 	switch (event) {
87839beb93cSSam Leffler 	case WPS_EV_M2D:
87939beb93cSSam Leffler 		wpa_supplicant_wps_event_m2d(wpa_s, &data->m2d);
88039beb93cSSam Leffler 		break;
88139beb93cSSam Leffler 	case WPS_EV_FAIL:
88239beb93cSSam Leffler 		wpa_supplicant_wps_event_fail(wpa_s, &data->fail);
88339beb93cSSam Leffler 		break;
88439beb93cSSam Leffler 	case WPS_EV_SUCCESS:
88539beb93cSSam Leffler 		wpa_supplicant_wps_event_success(wpa_s);
88639beb93cSSam Leffler 		break;
88739beb93cSSam Leffler 	case WPS_EV_PWD_AUTH_FAIL:
888f05cddf9SRui Paulo #ifdef CONFIG_AP
889f05cddf9SRui Paulo 		if (wpa_s->ap_iface && data->pwd_auth_fail.enrollee)
890f05cddf9SRui Paulo 			wpa_supplicant_ap_pwd_auth_fail(wpa_s);
891f05cddf9SRui Paulo #endif /* CONFIG_AP */
89239beb93cSSam Leffler 		break;
8933157ba21SRui Paulo 	case WPS_EV_PBC_OVERLAP:
8943157ba21SRui Paulo 		break;
8953157ba21SRui Paulo 	case WPS_EV_PBC_TIMEOUT:
8963157ba21SRui Paulo 		break;
8975b9c547cSRui Paulo 	case WPS_EV_PBC_ACTIVE:
8985b9c547cSRui Paulo 		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ACTIVE);
8995b9c547cSRui Paulo 		break;
9005b9c547cSRui Paulo 	case WPS_EV_PBC_DISABLE:
9015b9c547cSRui Paulo 		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_DISABLE);
9025b9c547cSRui Paulo 		break;
903e28a4053SRui Paulo 	case WPS_EV_ER_AP_ADD:
904e28a4053SRui Paulo 		wpa_supplicant_wps_event_er_ap_add(wpa_s, &data->ap);
905e28a4053SRui Paulo 		break;
906e28a4053SRui Paulo 	case WPS_EV_ER_AP_REMOVE:
907e28a4053SRui Paulo 		wpa_supplicant_wps_event_er_ap_remove(wpa_s, &data->ap);
908e28a4053SRui Paulo 		break;
909e28a4053SRui Paulo 	case WPS_EV_ER_ENROLLEE_ADD:
910e28a4053SRui Paulo 		wpa_supplicant_wps_event_er_enrollee_add(wpa_s,
911e28a4053SRui Paulo 							 &data->enrollee);
912e28a4053SRui Paulo 		break;
913e28a4053SRui Paulo 	case WPS_EV_ER_ENROLLEE_REMOVE:
914e28a4053SRui Paulo 		wpa_supplicant_wps_event_er_enrollee_remove(wpa_s,
915e28a4053SRui Paulo 							    &data->enrollee);
916e28a4053SRui Paulo 		break;
917f05cddf9SRui Paulo 	case WPS_EV_ER_AP_SETTINGS:
918f05cddf9SRui Paulo 		wpa_supplicant_wps_event_er_ap_settings(wpa_s,
919f05cddf9SRui Paulo 							&data->ap_settings);
920f05cddf9SRui Paulo 		break;
921f05cddf9SRui Paulo 	case WPS_EV_ER_SET_SELECTED_REGISTRAR:
922f05cddf9SRui Paulo 		wpa_supplicant_wps_event_er_set_sel_reg(wpa_s,
923f05cddf9SRui Paulo 							&data->set_sel_reg);
924f05cddf9SRui Paulo 		break;
925f05cddf9SRui Paulo 	case WPS_EV_AP_PIN_SUCCESS:
926f05cddf9SRui Paulo 		break;
92739beb93cSSam Leffler 	}
92839beb93cSSam Leffler }
92939beb93cSSam Leffler 
93039beb93cSSam Leffler 
wpa_supplicant_wps_rf_band(void * ctx)9315b9c547cSRui Paulo static int wpa_supplicant_wps_rf_band(void *ctx)
9325b9c547cSRui Paulo {
9335b9c547cSRui Paulo 	struct wpa_supplicant *wpa_s = ctx;
9345b9c547cSRui Paulo 
9355b9c547cSRui Paulo 	if (!wpa_s->current_ssid || !wpa_s->assoc_freq)
9365b9c547cSRui Paulo 		return 0;
9375b9c547cSRui Paulo 
938325151a3SRui Paulo 	return (wpa_s->assoc_freq > 50000) ? WPS_RF_60GHZ :
939325151a3SRui Paulo 		(wpa_s->assoc_freq > 2484) ? WPS_RF_50GHZ : WPS_RF_24GHZ;
9405b9c547cSRui Paulo }
9415b9c547cSRui Paulo 
9425b9c547cSRui Paulo 
wpas_wps_get_req_type(struct wpa_ssid * ssid)94339beb93cSSam Leffler enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid)
94439beb93cSSam Leffler {
94539beb93cSSam Leffler 	if (eap_is_wps_pbc_enrollee(&ssid->eap) ||
94639beb93cSSam Leffler 	    eap_is_wps_pin_enrollee(&ssid->eap))
94739beb93cSSam Leffler 		return WPS_REQ_ENROLLEE;
94839beb93cSSam Leffler 	else
94939beb93cSSam Leffler 		return WPS_REQ_REGISTRAR;
95039beb93cSSam Leffler }
95139beb93cSSam Leffler 
95239beb93cSSam Leffler 
wpas_clear_wps(struct wpa_supplicant * wpa_s)95339beb93cSSam Leffler static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
95439beb93cSSam Leffler {
95539beb93cSSam Leffler 	int id;
956f05cddf9SRui Paulo 	struct wpa_ssid *ssid, *remove_ssid = NULL, *prev_current;
957f05cddf9SRui Paulo 
9585b9c547cSRui Paulo 	wpa_s->after_wps = 0;
9595b9c547cSRui Paulo 	wpa_s->known_wps_freq = 0;
9605b9c547cSRui Paulo 
961f05cddf9SRui Paulo 	prev_current = wpa_s->current_ssid;
962f05cddf9SRui Paulo 
963f05cddf9SRui Paulo 	/* Enable the networks disabled during wpas_wps_reassoc */
964f05cddf9SRui Paulo 	wpas_wps_reenable_networks(wpa_s);
96539beb93cSSam Leffler 
96639beb93cSSam Leffler 	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
9675b9c547cSRui Paulo 	eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
96839beb93cSSam Leffler 
96939beb93cSSam Leffler 	/* Remove any existing WPS network from configuration */
97039beb93cSSam Leffler 	ssid = wpa_s->conf->ssid;
97139beb93cSSam Leffler 	while (ssid) {
97239beb93cSSam Leffler 		if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
973e28a4053SRui Paulo 			if (ssid == wpa_s->current_ssid) {
9745b9c547cSRui Paulo 				wpa_s->own_disconnect_req = 1;
9755b9c547cSRui Paulo 				wpa_supplicant_deauthenticate(
9765b9c547cSRui Paulo 					wpa_s, WLAN_REASON_DEAUTH_LEAVING);
977e28a4053SRui Paulo 			}
97839beb93cSSam Leffler 			id = ssid->id;
979e28a4053SRui Paulo 			remove_ssid = ssid;
98039beb93cSSam Leffler 		} else
98139beb93cSSam Leffler 			id = -1;
98239beb93cSSam Leffler 		ssid = ssid->next;
983e28a4053SRui Paulo 		if (id >= 0) {
984f05cddf9SRui Paulo 			if (prev_current == remove_ssid) {
985f05cddf9SRui Paulo 				wpa_sm_set_config(wpa_s->wpa, NULL);
986f05cddf9SRui Paulo 				eapol_sm_notify_config(wpa_s->eapol, NULL,
987f05cddf9SRui Paulo 						       NULL);
988f05cddf9SRui Paulo 			}
989e28a4053SRui Paulo 			wpas_notify_network_removed(wpa_s, remove_ssid);
99039beb93cSSam Leffler 			wpa_config_remove_network(wpa_s->conf, id);
99139beb93cSSam Leffler 		}
99239beb93cSSam Leffler 	}
993f05cddf9SRui Paulo 
994f05cddf9SRui Paulo 	wpas_wps_clear_ap_info(wpa_s);
995e28a4053SRui Paulo }
99639beb93cSSam Leffler 
99739beb93cSSam Leffler 
wpas_wps_timeout(void * eloop_ctx,void * timeout_ctx)99839beb93cSSam Leffler static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
99939beb93cSSam Leffler {
100039beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = eloop_ctx;
1001325151a3SRui Paulo 	union wps_event_data data;
1002325151a3SRui Paulo 
1003f05cddf9SRui Paulo 	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed "
100439beb93cSSam Leffler 		"out");
1005325151a3SRui Paulo 	os_memset(&data, 0, sizeof(data));
1006325151a3SRui Paulo 	data.fail.config_error = WPS_CFG_MSG_TIMEOUT;
1007325151a3SRui Paulo 	data.fail.error_indication = WPS_EI_NO_ERROR;
1008325151a3SRui Paulo 	/*
1009325151a3SRui Paulo 	 * Call wpas_notify_wps_event_fail() directly instead of through
1010325151a3SRui Paulo 	 * wpa_supplicant_wps_event() which would end up registering unnecessary
1011325151a3SRui Paulo 	 * timeouts (those are only for the case where the failure happens
1012325151a3SRui Paulo 	 * during an EAP-WSC exchange).
1013325151a3SRui Paulo 	 */
1014325151a3SRui Paulo 	wpas_notify_wps_event_fail(wpa_s, &data.fail);
1015*a90b9d01SCy Schubert 	wpa_s->supp_pbc_active = false;
1016*a90b9d01SCy Schubert 	wpa_s->wps_overlap = false;
101739beb93cSSam Leffler 	wpas_clear_wps(wpa_s);
101839beb93cSSam Leffler }
101939beb93cSSam Leffler 
102039beb93cSSam Leffler 
wpas_wps_add_network(struct wpa_supplicant * wpa_s,int registrar,const u8 * dev_addr,const u8 * bssid)102139beb93cSSam Leffler static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
10225b9c547cSRui Paulo 					      int registrar, const u8 *dev_addr,
10235b9c547cSRui Paulo 					      const u8 *bssid)
102439beb93cSSam Leffler {
102539beb93cSSam Leffler 	struct wpa_ssid *ssid;
102639beb93cSSam Leffler 
102739beb93cSSam Leffler 	ssid = wpa_config_add_network(wpa_s->conf);
102839beb93cSSam Leffler 	if (ssid == NULL)
102939beb93cSSam Leffler 		return NULL;
1030e28a4053SRui Paulo 	wpas_notify_network_added(wpa_s, ssid);
103139beb93cSSam Leffler 	wpa_config_set_network_defaults(ssid);
1032f05cddf9SRui Paulo 	ssid->temporary = 1;
103339beb93cSSam Leffler 	if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 ||
103439beb93cSSam Leffler 	    wpa_config_set(ssid, "eap", "WSC", 0) < 0 ||
103539beb93cSSam Leffler 	    wpa_config_set(ssid, "identity", registrar ?
103639beb93cSSam Leffler 			   "\"" WSC_ID_REGISTRAR "\"" :
103739beb93cSSam Leffler 			   "\"" WSC_ID_ENROLLEE "\"", 0) < 0) {
1038e28a4053SRui Paulo 		wpas_notify_network_removed(wpa_s, ssid);
103939beb93cSSam Leffler 		wpa_config_remove_network(wpa_s->conf, ssid->id);
104039beb93cSSam Leffler 		return NULL;
104139beb93cSSam Leffler 	}
104239beb93cSSam Leffler 
10435b9c547cSRui Paulo #ifdef CONFIG_P2P
10445b9c547cSRui Paulo 	if (dev_addr)
10455b9c547cSRui Paulo 		os_memcpy(ssid->go_p2p_dev_addr, dev_addr, ETH_ALEN);
10465b9c547cSRui Paulo #endif /* CONFIG_P2P */
10475b9c547cSRui Paulo 
104839beb93cSSam Leffler 	if (bssid) {
1049f05cddf9SRui Paulo #ifndef CONFIG_P2P
1050e28a4053SRui Paulo 		struct wpa_bss *bss;
10513157ba21SRui Paulo 		int count = 0;
1052f05cddf9SRui Paulo #endif /* CONFIG_P2P */
105339beb93cSSam Leffler 
105439beb93cSSam Leffler 		os_memcpy(ssid->bssid, bssid, ETH_ALEN);
105539beb93cSSam Leffler 		ssid->bssid_set = 1;
105639beb93cSSam Leffler 
1057f05cddf9SRui Paulo 		/*
1058f05cddf9SRui Paulo 		 * Note: With P2P, the SSID may change at the time the WPS
1059f05cddf9SRui Paulo 		 * provisioning is started, so better not filter the AP based
1060f05cddf9SRui Paulo 		 * on the current SSID in the scan results.
1061f05cddf9SRui Paulo 		 */
1062f05cddf9SRui Paulo #ifndef CONFIG_P2P
1063e28a4053SRui Paulo 		dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
1064*a90b9d01SCy Schubert 			if (!ether_addr_equal(bssid, bss->bssid))
106539beb93cSSam Leffler 				continue;
106639beb93cSSam Leffler 
106739beb93cSSam Leffler 			os_free(ssid->ssid);
106885732ac8SCy Schubert 			ssid->ssid = os_memdup(bss->ssid, bss->ssid_len);
106939beb93cSSam Leffler 			if (ssid->ssid == NULL)
107039beb93cSSam Leffler 				break;
1071e28a4053SRui Paulo 			ssid->ssid_len = bss->ssid_len;
10723157ba21SRui Paulo 			wpa_hexdump_ascii(MSG_DEBUG, "WPS: Picked SSID from "
10733157ba21SRui Paulo 					  "scan results",
10743157ba21SRui Paulo 					  ssid->ssid, ssid->ssid_len);
10753157ba21SRui Paulo 			count++;
10763157ba21SRui Paulo 		}
10773157ba21SRui Paulo 
10783157ba21SRui Paulo 		if (count > 1) {
10793157ba21SRui Paulo 			wpa_printf(MSG_DEBUG, "WPS: More than one SSID found "
10803157ba21SRui Paulo 				   "for the AP; use wildcard");
10813157ba21SRui Paulo 			os_free(ssid->ssid);
10823157ba21SRui Paulo 			ssid->ssid = NULL;
10833157ba21SRui Paulo 			ssid->ssid_len = 0;
108439beb93cSSam Leffler 		}
1085f05cddf9SRui Paulo #endif /* CONFIG_P2P */
108639beb93cSSam Leffler 	}
108739beb93cSSam Leffler 
108839beb93cSSam Leffler 	return ssid;
108939beb93cSSam Leffler }
109039beb93cSSam Leffler 
109139beb93cSSam Leffler 
wpas_wps_temp_disable(struct wpa_supplicant * wpa_s,struct wpa_ssid * selected)10925b9c547cSRui Paulo static void wpas_wps_temp_disable(struct wpa_supplicant *wpa_s,
10935b9c547cSRui Paulo 				  struct wpa_ssid *selected)
109439beb93cSSam Leffler {
109539beb93cSSam Leffler 	struct wpa_ssid *ssid;
1096f05cddf9SRui Paulo 
10975b9c547cSRui Paulo 	if (wpa_s->current_ssid) {
10985b9c547cSRui Paulo 		wpa_s->own_disconnect_req = 1;
1099f05cddf9SRui Paulo 		wpa_supplicant_deauthenticate(
1100f05cddf9SRui Paulo 			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
11015b9c547cSRui Paulo 	}
110239beb93cSSam Leffler 
110339beb93cSSam Leffler 	/* Mark all other networks disabled and trigger reassociation */
110439beb93cSSam Leffler 	ssid = wpa_s->conf->ssid;
110539beb93cSSam Leffler 	while (ssid) {
1106e28a4053SRui Paulo 		int was_disabled = ssid->disabled;
1107f05cddf9SRui Paulo 		ssid->disabled_for_connect = 0;
1108f05cddf9SRui Paulo 		/*
1109f05cddf9SRui Paulo 		 * In case the network object corresponds to a persistent group
1110f05cddf9SRui Paulo 		 * then do not send out network disabled signal. In addition,
1111f05cddf9SRui Paulo 		 * do not change disabled status of persistent network objects
1112f05cddf9SRui Paulo 		 * from 2 to 1 should we connect to another network.
1113f05cddf9SRui Paulo 		 */
1114f05cddf9SRui Paulo 		if (was_disabled != 2) {
111539beb93cSSam Leffler 			ssid->disabled = ssid != selected;
1116f05cddf9SRui Paulo 			if (was_disabled != ssid->disabled) {
1117f05cddf9SRui Paulo 				if (ssid->disabled)
1118f05cddf9SRui Paulo 					ssid->disabled_for_connect = 1;
1119f05cddf9SRui Paulo 				wpas_notify_network_enabled_changed(wpa_s,
1120f05cddf9SRui Paulo 								    ssid);
1121f05cddf9SRui Paulo 			}
1122f05cddf9SRui Paulo 		}
112339beb93cSSam Leffler 		ssid = ssid->next;
112439beb93cSSam Leffler 	}
11255b9c547cSRui Paulo }
11265b9c547cSRui Paulo 
11275b9c547cSRui Paulo 
wpas_wps_reassoc(struct wpa_supplicant * wpa_s,struct wpa_ssid * selected,const u8 * bssid,int freq)11285b9c547cSRui Paulo static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
11295b9c547cSRui Paulo 			     struct wpa_ssid *selected, const u8 *bssid,
11305b9c547cSRui Paulo 			     int freq)
11315b9c547cSRui Paulo {
11325b9c547cSRui Paulo 	struct wpa_bss *bss;
11335b9c547cSRui Paulo 
11345b9c547cSRui Paulo 	wpa_s->wps_run++;
11355b9c547cSRui Paulo 	if (wpa_s->wps_run == 0)
11365b9c547cSRui Paulo 		wpa_s->wps_run++;
11375b9c547cSRui Paulo 	wpa_s->after_wps = 0;
11385b9c547cSRui Paulo 	wpa_s->known_wps_freq = 0;
11395b9c547cSRui Paulo 	if (freq) {
11405b9c547cSRui Paulo 		wpa_s->after_wps = 5;
11415b9c547cSRui Paulo 		wpa_s->wps_freq = freq;
11425b9c547cSRui Paulo 	} else if (bssid) {
11435b9c547cSRui Paulo 		bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
11445b9c547cSRui Paulo 		if (bss && bss->freq > 0) {
11455b9c547cSRui Paulo 			wpa_s->known_wps_freq = 1;
11465b9c547cSRui Paulo 			wpa_s->wps_freq = bss->freq;
11475b9c547cSRui Paulo 		}
11485b9c547cSRui Paulo 	}
11495b9c547cSRui Paulo 
11505b9c547cSRui Paulo 	wpas_wps_temp_disable(wpa_s, selected);
11515b9c547cSRui Paulo 
115239beb93cSSam Leffler 	wpa_s->disconnected = 0;
115339beb93cSSam Leffler 	wpa_s->reassociate = 1;
115439beb93cSSam Leffler 	wpa_s->scan_runs = 0;
1155f05cddf9SRui Paulo 	wpa_s->normal_scans = 0;
115639beb93cSSam Leffler 	wpa_s->wps_success = 0;
1157c1d255d3SCy Schubert 	wpa_s->bssid_ignore_cleared = false;
11585b9c547cSRui Paulo 
11595b9c547cSRui Paulo 	wpa_supplicant_cancel_sched_scan(wpa_s);
116039beb93cSSam Leffler 	wpa_supplicant_req_scan(wpa_s, 0, 0);
116139beb93cSSam Leffler }
116239beb93cSSam Leffler 
116339beb93cSSam Leffler 
wpas_wps_start_pbc(struct wpa_supplicant * wpa_s,const u8 * bssid,int p2p_group,int multi_ap_backhaul_sta)1164f05cddf9SRui Paulo int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
11654bc52338SCy Schubert 		       int p2p_group, int multi_ap_backhaul_sta)
116639beb93cSSam Leffler {
116739beb93cSSam Leffler 	struct wpa_ssid *ssid;
11684bc52338SCy Schubert 	char phase1[32];
11695b9c547cSRui Paulo 
11705b9c547cSRui Paulo #ifdef CONFIG_AP
11715b9c547cSRui Paulo 	if (wpa_s->ap_iface) {
11725b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG,
11735b9c547cSRui Paulo 			   "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
11745b9c547cSRui Paulo 		return -1;
11755b9c547cSRui Paulo 	}
11765b9c547cSRui Paulo #endif /* CONFIG_AP */
117739beb93cSSam Leffler 	wpas_clear_wps(wpa_s);
11785b9c547cSRui Paulo 	ssid = wpas_wps_add_network(wpa_s, 0, NULL, bssid);
117939beb93cSSam Leffler 	if (ssid == NULL)
118039beb93cSSam Leffler 		return -1;
1181f05cddf9SRui Paulo 	ssid->temporary = 1;
1182f05cddf9SRui Paulo 	ssid->p2p_group = p2p_group;
1183780fb4a2SCy Schubert 	/*
1184780fb4a2SCy Schubert 	 * When starting a regular WPS process (not P2P group formation)
1185780fb4a2SCy Schubert 	 * the registrar/final station can be either AP or PCP
1186780fb4a2SCy Schubert 	 * so use a "don't care" value for the pbss flag.
1187780fb4a2SCy Schubert 	 */
1188780fb4a2SCy Schubert 	if (!p2p_group)
1189780fb4a2SCy Schubert 		ssid->pbss = 2;
1190f05cddf9SRui Paulo #ifdef CONFIG_P2P
1191f05cddf9SRui Paulo 	if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
1192f05cddf9SRui Paulo 		ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
1193f05cddf9SRui Paulo 		if (ssid->ssid) {
1194f05cddf9SRui Paulo 			ssid->ssid_len = wpa_s->go_params->ssid_len;
1195f05cddf9SRui Paulo 			os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
1196f05cddf9SRui Paulo 				  ssid->ssid_len);
1197780fb4a2SCy Schubert 			if (wpa_s->go_params->freq > 56160) {
1198780fb4a2SCy Schubert 				/* P2P in 60 GHz uses PBSS */
1199780fb4a2SCy Schubert 				ssid->pbss = 1;
1200780fb4a2SCy Schubert 			}
1201c1d255d3SCy Schubert 			if (wpa_s->go_params->edmg &&
1202c1d255d3SCy Schubert 			    wpas_p2p_try_edmg_channel(wpa_s,
1203c1d255d3SCy Schubert 						      wpa_s->go_params) == 0)
1204c1d255d3SCy Schubert 				ssid->enable_edmg = 1;
1205c1d255d3SCy Schubert 
1206f05cddf9SRui Paulo 			wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
1207f05cddf9SRui Paulo 					  "SSID", ssid->ssid, ssid->ssid_len);
1208f05cddf9SRui Paulo 		}
1209f05cddf9SRui Paulo 	}
1210f05cddf9SRui Paulo #endif /* CONFIG_P2P */
1211*a90b9d01SCy Schubert 	if (multi_ap_backhaul_sta)
1212*a90b9d01SCy Schubert 		os_snprintf(phase1, sizeof(phase1), "pbc=1 multi_ap=%d",
1213*a90b9d01SCy Schubert 			    multi_ap_backhaul_sta);
1214*a90b9d01SCy Schubert 	else
1215*a90b9d01SCy Schubert 		os_snprintf(phase1, sizeof(phase1), "pbc=1");
12164bc52338SCy Schubert 	if (wpa_config_set_quoted(ssid, "phase1", phase1) < 0)
12175b9c547cSRui Paulo 		return -1;
1218f05cddf9SRui Paulo 	if (wpa_s->wps_fragment_size)
1219f05cddf9SRui Paulo 		ssid->eap.fragment_size = wpa_s->wps_fragment_size;
1220*a90b9d01SCy Schubert 	if (multi_ap_backhaul_sta) {
12214bc52338SCy Schubert 		ssid->multi_ap_backhaul_sta = 1;
1222*a90b9d01SCy Schubert 		ssid->multi_ap_profile = multi_ap_backhaul_sta;
1223*a90b9d01SCy Schubert 	}
1224*a90b9d01SCy Schubert 	wpa_s->supp_pbc_active = true;
1225*a90b9d01SCy Schubert 	wpa_s->wps_overlap = false;
122685732ac8SCy Schubert 	wpa_supplicant_wps_event(wpa_s, WPS_EV_PBC_ACTIVE, NULL);
122739beb93cSSam Leffler 	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
122839beb93cSSam Leffler 			       wpa_s, NULL);
12295b9c547cSRui Paulo 	wpas_wps_reassoc(wpa_s, ssid, bssid, 0);
123039beb93cSSam Leffler 	return 0;
123139beb93cSSam Leffler }
123239beb93cSSam Leffler 
123339beb93cSSam Leffler 
wpas_wps_start_dev_pw(struct wpa_supplicant * wpa_s,const u8 * dev_addr,const u8 * bssid,const char * pin,int p2p_group,u16 dev_pw_id,const u8 * peer_pubkey_hash,const u8 * ssid_val,size_t ssid_len,int freq)12345b9c547cSRui Paulo static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
12355b9c547cSRui Paulo 				 const u8 *dev_addr, const u8 *bssid,
12365b9c547cSRui Paulo 				 const char *pin, int p2p_group, u16 dev_pw_id,
12375b9c547cSRui Paulo 				 const u8 *peer_pubkey_hash,
12385b9c547cSRui Paulo 				 const u8 *ssid_val, size_t ssid_len, int freq)
123939beb93cSSam Leffler {
124039beb93cSSam Leffler 	struct wpa_ssid *ssid;
12415b9c547cSRui Paulo 	char val[128 + 2 * WPS_OOB_PUBKEY_HASH_LEN];
124239beb93cSSam Leffler 	unsigned int rpin = 0;
12435b9c547cSRui Paulo 	char hash[2 * WPS_OOB_PUBKEY_HASH_LEN + 10];
124439beb93cSSam Leffler 
12455b9c547cSRui Paulo #ifdef CONFIG_AP
12465b9c547cSRui Paulo 	if (wpa_s->ap_iface) {
12475b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG,
12485b9c547cSRui Paulo 			   "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
124939beb93cSSam Leffler 		return -1;
12505b9c547cSRui Paulo 	}
12515b9c547cSRui Paulo #endif /* CONFIG_AP */
12525b9c547cSRui Paulo 	wpas_clear_wps(wpa_s);
12535b9c547cSRui Paulo 	if (bssid && is_zero_ether_addr(bssid))
12545b9c547cSRui Paulo 		bssid = NULL;
12555b9c547cSRui Paulo 	ssid = wpas_wps_add_network(wpa_s, 0, dev_addr, bssid);
12565b9c547cSRui Paulo 	if (ssid == NULL) {
12575b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Could not add network");
12585b9c547cSRui Paulo 		return -1;
12595b9c547cSRui Paulo 	}
1260f05cddf9SRui Paulo 	ssid->temporary = 1;
1261f05cddf9SRui Paulo 	ssid->p2p_group = p2p_group;
1262780fb4a2SCy Schubert 	/*
1263780fb4a2SCy Schubert 	 * When starting a regular WPS process (not P2P group formation)
1264780fb4a2SCy Schubert 	 * the registrar/final station can be either AP or PCP
1265780fb4a2SCy Schubert 	 * so use a "don't care" value for the pbss flag.
1266780fb4a2SCy Schubert 	 */
1267780fb4a2SCy Schubert 	if (!p2p_group)
1268780fb4a2SCy Schubert 		ssid->pbss = 2;
12695b9c547cSRui Paulo 	if (ssid_val) {
12705b9c547cSRui Paulo 		ssid->ssid = os_malloc(ssid_len);
12715b9c547cSRui Paulo 		if (ssid->ssid) {
12725b9c547cSRui Paulo 			os_memcpy(ssid->ssid, ssid_val, ssid_len);
12735b9c547cSRui Paulo 			ssid->ssid_len = ssid_len;
12745b9c547cSRui Paulo 		}
12755b9c547cSRui Paulo 	}
12765b9c547cSRui Paulo 	if (peer_pubkey_hash) {
12775b9c547cSRui Paulo 		os_memcpy(hash, " pkhash=", 8);
12785b9c547cSRui Paulo 		wpa_snprintf_hex_uppercase(hash + 8, sizeof(hash) - 8,
12795b9c547cSRui Paulo 					   peer_pubkey_hash,
12805b9c547cSRui Paulo 					   WPS_OOB_PUBKEY_HASH_LEN);
12815b9c547cSRui Paulo 	} else {
12825b9c547cSRui Paulo 		hash[0] = '\0';
12835b9c547cSRui Paulo 	}
1284f05cddf9SRui Paulo #ifdef CONFIG_P2P
1285f05cddf9SRui Paulo 	if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
1286325151a3SRui Paulo 		os_free(ssid->ssid);
1287f05cddf9SRui Paulo 		ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
1288f05cddf9SRui Paulo 		if (ssid->ssid) {
1289f05cddf9SRui Paulo 			ssid->ssid_len = wpa_s->go_params->ssid_len;
1290f05cddf9SRui Paulo 			os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
1291f05cddf9SRui Paulo 				  ssid->ssid_len);
1292780fb4a2SCy Schubert 			if (wpa_s->go_params->freq > 56160) {
1293780fb4a2SCy Schubert 				/* P2P in 60 GHz uses PBSS */
1294780fb4a2SCy Schubert 				ssid->pbss = 1;
1295780fb4a2SCy Schubert 			}
1296c1d255d3SCy Schubert 			if (wpa_s->go_params->edmg &&
1297c1d255d3SCy Schubert 			    wpas_p2p_try_edmg_channel(wpa_s,
1298c1d255d3SCy Schubert 						      wpa_s->go_params) == 0)
1299c1d255d3SCy Schubert 				ssid->enable_edmg = 1;
1300c1d255d3SCy Schubert 
1301f05cddf9SRui Paulo 			wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
1302f05cddf9SRui Paulo 					  "SSID", ssid->ssid, ssid->ssid_len);
1303f05cddf9SRui Paulo 		}
1304f05cddf9SRui Paulo 	}
1305f05cddf9SRui Paulo #endif /* CONFIG_P2P */
130639beb93cSSam Leffler 	if (pin)
13075b9c547cSRui Paulo 		os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u%s\"",
13085b9c547cSRui Paulo 			    pin, dev_pw_id, hash);
13095b9c547cSRui Paulo 	else if (pin == NULL && dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) {
13105b9c547cSRui Paulo 		os_snprintf(val, sizeof(val), "\"dev_pw_id=%u%s\"",
13115b9c547cSRui Paulo 			    dev_pw_id, hash);
13125b9c547cSRui Paulo 	} else {
1313780fb4a2SCy Schubert 		if (wps_generate_pin(&rpin) < 0) {
1314780fb4a2SCy Schubert 			wpa_printf(MSG_DEBUG, "WPS: Could not generate PIN");
1315780fb4a2SCy Schubert 			return -1;
1316780fb4a2SCy Schubert 		}
13175b9c547cSRui Paulo 		os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u%s\"",
13185b9c547cSRui Paulo 			    rpin, dev_pw_id, hash);
131939beb93cSSam Leffler 	}
13205b9c547cSRui Paulo 	if (wpa_config_set(ssid, "phase1", val, 0) < 0) {
13215b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Failed to set phase1 '%s'", val);
13225b9c547cSRui Paulo 		return -1;
13235b9c547cSRui Paulo 	}
1324c1d255d3SCy Schubert 
1325c1d255d3SCy Schubert 	if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER)
1326c1d255d3SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_PIN_ACTIVE);
1327c1d255d3SCy Schubert 
1328f05cddf9SRui Paulo 	if (wpa_s->wps_fragment_size)
1329f05cddf9SRui Paulo 		ssid->eap.fragment_size = wpa_s->wps_fragment_size;
133039beb93cSSam Leffler 	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
133139beb93cSSam Leffler 			       wpa_s, NULL);
1332f05cddf9SRui Paulo 	wpa_s->wps_ap_iter = 1;
13335b9c547cSRui Paulo 	wpas_wps_reassoc(wpa_s, ssid, bssid, freq);
133439beb93cSSam Leffler 	return rpin;
133539beb93cSSam Leffler }
133639beb93cSSam Leffler 
133739beb93cSSam Leffler 
wpas_wps_start_pin(struct wpa_supplicant * wpa_s,const u8 * bssid,const char * pin,int p2p_group,u16 dev_pw_id)13385b9c547cSRui Paulo int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
13395b9c547cSRui Paulo 		       const char *pin, int p2p_group, u16 dev_pw_id)
13405b9c547cSRui Paulo {
1341325151a3SRui Paulo 	os_get_reltime(&wpa_s->wps_pin_start_time);
13425b9c547cSRui Paulo 	return wpas_wps_start_dev_pw(wpa_s, NULL, bssid, pin, p2p_group,
13435b9c547cSRui Paulo 				     dev_pw_id, NULL, NULL, 0, 0);
13445b9c547cSRui Paulo }
13455b9c547cSRui Paulo 
13465b9c547cSRui Paulo 
wpas_wps_pbc_overlap(struct wpa_supplicant * wpa_s)1347325151a3SRui Paulo void wpas_wps_pbc_overlap(struct wpa_supplicant *wpa_s)
1348325151a3SRui Paulo {
1349325151a3SRui Paulo 	union wps_event_data data;
1350325151a3SRui Paulo 
1351325151a3SRui Paulo 	os_memset(&data, 0, sizeof(data));
1352325151a3SRui Paulo 	data.fail.config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
1353325151a3SRui Paulo 	data.fail.error_indication = WPS_EI_NO_ERROR;
1354325151a3SRui Paulo 	/*
1355325151a3SRui Paulo 	 * Call wpas_notify_wps_event_fail() directly instead of through
1356325151a3SRui Paulo 	 * wpa_supplicant_wps_event() which would end up registering unnecessary
1357325151a3SRui Paulo 	 * timeouts (those are only for the case where the failure happens
1358325151a3SRui Paulo 	 * during an EAP-WSC exchange).
1359325151a3SRui Paulo 	 */
1360325151a3SRui Paulo 	wpas_notify_wps_event_fail(wpa_s, &data.fail);
1361325151a3SRui Paulo }
1362325151a3SRui Paulo 
1363f05cddf9SRui Paulo /* Cancel the wps pbc/pin requests */
wpas_wps_cancel(struct wpa_supplicant * wpa_s)1364f05cddf9SRui Paulo int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
1365e28a4053SRui Paulo {
1366f05cddf9SRui Paulo #ifdef CONFIG_AP
1367f05cddf9SRui Paulo 	if (wpa_s->ap_iface) {
1368f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Cancelling in AP mode");
1369f05cddf9SRui Paulo 		return wpa_supplicant_ap_wps_cancel(wpa_s);
1370e28a4053SRui Paulo 	}
1371f05cddf9SRui Paulo #endif /* CONFIG_AP */
1372e28a4053SRui Paulo 
1373f05cddf9SRui Paulo 	if (wpa_s->wpa_state == WPA_SCANNING ||
1374f05cddf9SRui Paulo 	    wpa_s->wpa_state == WPA_DISCONNECTED) {
1375f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Cancel operation - cancel scan");
1376f05cddf9SRui Paulo 		wpa_supplicant_cancel_scan(wpa_s);
1377e28a4053SRui Paulo 		wpas_clear_wps(wpa_s);
1378f05cddf9SRui Paulo 	} else if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
1379f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Cancel operation - "
1380f05cddf9SRui Paulo 			   "deauthenticate");
13815b9c547cSRui Paulo 		wpa_s->own_disconnect_req = 1;
1382f05cddf9SRui Paulo 		wpa_supplicant_deauthenticate(wpa_s,
1383f05cddf9SRui Paulo 					      WLAN_REASON_DEAUTH_LEAVING);
1384f05cddf9SRui Paulo 		wpas_clear_wps(wpa_s);
1385f05cddf9SRui Paulo 	} else {
1386f05cddf9SRui Paulo 		wpas_wps_reenable_networks(wpa_s);
1387f05cddf9SRui Paulo 		wpas_wps_clear_ap_info(wpa_s);
13885b9c547cSRui Paulo 		if (eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL) >
13895b9c547cSRui Paulo 		    0)
13905b9c547cSRui Paulo 			wpas_clear_wps(wpa_s);
1391f05cddf9SRui Paulo 	}
1392e28a4053SRui Paulo 
1393*a90b9d01SCy Schubert 	wpa_s->supp_pbc_active = false;
1394*a90b9d01SCy Schubert 	wpa_s->wps_overlap = false;
1395c1d255d3SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CANCEL);
13965b9c547cSRui Paulo 	wpa_s->after_wps = 0;
13975b9c547cSRui Paulo 
1398e28a4053SRui Paulo 	return 0;
1399e28a4053SRui Paulo }
1400e28a4053SRui Paulo 
1401e28a4053SRui Paulo 
wpas_wps_start_reg(struct wpa_supplicant * wpa_s,const u8 * bssid,const char * pin,struct wps_new_ap_settings * settings)140239beb93cSSam Leffler int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
1403e28a4053SRui Paulo 		       const char *pin, struct wps_new_ap_settings *settings)
140439beb93cSSam Leffler {
140539beb93cSSam Leffler 	struct wpa_ssid *ssid;
1406e28a4053SRui Paulo 	char val[200];
1407e28a4053SRui Paulo 	char *pos, *end;
1408e28a4053SRui Paulo 	int res;
140939beb93cSSam Leffler 
14105b9c547cSRui Paulo #ifdef CONFIG_AP
14115b9c547cSRui Paulo 	if (wpa_s->ap_iface) {
14125b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG,
14135b9c547cSRui Paulo 			   "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
14145b9c547cSRui Paulo 		return -1;
14155b9c547cSRui Paulo 	}
14165b9c547cSRui Paulo #endif /* CONFIG_AP */
141739beb93cSSam Leffler 	if (!pin)
141839beb93cSSam Leffler 		return -1;
141939beb93cSSam Leffler 	wpas_clear_wps(wpa_s);
14205b9c547cSRui Paulo 	ssid = wpas_wps_add_network(wpa_s, 1, NULL, bssid);
142139beb93cSSam Leffler 	if (ssid == NULL)
142239beb93cSSam Leffler 		return -1;
1423f05cddf9SRui Paulo 	ssid->temporary = 1;
1424e28a4053SRui Paulo 	pos = val;
1425e28a4053SRui Paulo 	end = pos + sizeof(val);
1426e28a4053SRui Paulo 	res = os_snprintf(pos, end - pos, "\"pin=%s", pin);
14275b9c547cSRui Paulo 	if (os_snprintf_error(end - pos, res))
1428e28a4053SRui Paulo 		return -1;
1429e28a4053SRui Paulo 	pos += res;
1430e28a4053SRui Paulo 	if (settings) {
1431e28a4053SRui Paulo 		res = os_snprintf(pos, end - pos, " new_ssid=%s new_auth=%s "
1432e28a4053SRui Paulo 				  "new_encr=%s new_key=%s",
1433e28a4053SRui Paulo 				  settings->ssid_hex, settings->auth,
1434e28a4053SRui Paulo 				  settings->encr, settings->key_hex);
14355b9c547cSRui Paulo 		if (os_snprintf_error(end - pos, res))
1436e28a4053SRui Paulo 			return -1;
1437e28a4053SRui Paulo 		pos += res;
1438e28a4053SRui Paulo 	}
1439e28a4053SRui Paulo 	res = os_snprintf(pos, end - pos, "\"");
14405b9c547cSRui Paulo 	if (os_snprintf_error(end - pos, res))
1441e28a4053SRui Paulo 		return -1;
14425b9c547cSRui Paulo 	if (wpa_config_set(ssid, "phase1", val, 0) < 0)
14435b9c547cSRui Paulo 		return -1;
1444f05cddf9SRui Paulo 	if (wpa_s->wps_fragment_size)
1445f05cddf9SRui Paulo 		ssid->eap.fragment_size = wpa_s->wps_fragment_size;
144639beb93cSSam Leffler 	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
144739beb93cSSam Leffler 			       wpa_s, NULL);
14485b9c547cSRui Paulo 	wpas_wps_reassoc(wpa_s, ssid, bssid, 0);
144939beb93cSSam Leffler 	return 0;
145039beb93cSSam Leffler }
145139beb93cSSam Leffler 
145239beb93cSSam Leffler 
wpas_wps_new_psk_cb(void * ctx,const u8 * mac_addr,const u8 * p2p_dev_addr,const u8 * psk,size_t psk_len)14535b9c547cSRui Paulo static int wpas_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
14545b9c547cSRui Paulo 			       const u8 *p2p_dev_addr, const u8 *psk,
145539beb93cSSam Leffler 			       size_t psk_len)
145639beb93cSSam Leffler {
14575b9c547cSRui Paulo 	if (is_zero_ether_addr(p2p_dev_addr)) {
14585b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG,
14595b9c547cSRui Paulo 			   "Received new WPA/WPA2-PSK from WPS for STA " MACSTR,
14605b9c547cSRui Paulo 			   MAC2STR(mac_addr));
14615b9c547cSRui Paulo 	} else {
14625b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG,
14635b9c547cSRui Paulo 			   "Received new WPA/WPA2-PSK from WPS for STA " MACSTR
14645b9c547cSRui Paulo 			   " P2P Device Addr " MACSTR,
14655b9c547cSRui Paulo 			   MAC2STR(mac_addr), MAC2STR(p2p_dev_addr));
14665b9c547cSRui Paulo 	}
146739beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
146839beb93cSSam Leffler 
146939beb93cSSam Leffler 	/* TODO */
147039beb93cSSam Leffler 
147139beb93cSSam Leffler 	return 0;
147239beb93cSSam Leffler }
147339beb93cSSam Leffler 
147439beb93cSSam Leffler 
wpas_wps_pin_needed_cb(void * ctx,const u8 * uuid_e,const struct wps_device_data * dev)147539beb93cSSam Leffler static void wpas_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
147639beb93cSSam Leffler 				   const struct wps_device_data *dev)
147739beb93cSSam Leffler {
147839beb93cSSam Leffler 	char uuid[40], txt[400];
147939beb93cSSam Leffler 	int len;
1480e28a4053SRui Paulo 	char devtype[WPS_DEV_TYPE_BUFSIZE];
148139beb93cSSam Leffler 	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
148239beb93cSSam Leffler 		return;
148339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: PIN needed for UUID-E %s", uuid);
148439beb93cSSam Leffler 	len = os_snprintf(txt, sizeof(txt), "WPS-EVENT-PIN-NEEDED %s " MACSTR
1485e28a4053SRui Paulo 			  " [%s|%s|%s|%s|%s|%s]",
148639beb93cSSam Leffler 			  uuid, MAC2STR(dev->mac_addr), dev->device_name,
148739beb93cSSam Leffler 			  dev->manufacturer, dev->model_name,
148839beb93cSSam Leffler 			  dev->model_number, dev->serial_number,
1489e28a4053SRui Paulo 			  wps_dev_type_bin2str(dev->pri_dev_type, devtype,
1490e28a4053SRui Paulo 					       sizeof(devtype)));
14915b9c547cSRui Paulo 	if (!os_snprintf_error(sizeof(txt), len))
149239beb93cSSam Leffler 		wpa_printf(MSG_INFO, "%s", txt);
149339beb93cSSam Leffler }
149439beb93cSSam Leffler 
149539beb93cSSam Leffler 
wpas_wps_set_sel_reg_cb(void * ctx,int sel_reg,u16 dev_passwd_id,u16 sel_reg_config_methods)1496e28a4053SRui Paulo static void wpas_wps_set_sel_reg_cb(void *ctx, int sel_reg, u16 dev_passwd_id,
1497e28a4053SRui Paulo 				    u16 sel_reg_config_methods)
1498e28a4053SRui Paulo {
1499e28a4053SRui Paulo #ifdef CONFIG_WPS_ER
1500e28a4053SRui Paulo 	struct wpa_supplicant *wpa_s = ctx;
1501e28a4053SRui Paulo 
1502e28a4053SRui Paulo 	if (wpa_s->wps_er == NULL)
1503e28a4053SRui Paulo 		return;
1504f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar - sel_reg=%d "
1505f05cddf9SRui Paulo 		   "dev_password_id=%u sel_reg_config_methods=0x%x",
1506f05cddf9SRui Paulo 		   sel_reg, dev_passwd_id, sel_reg_config_methods);
1507e28a4053SRui Paulo 	wps_er_set_sel_reg(wpa_s->wps_er, sel_reg, dev_passwd_id,
1508e28a4053SRui Paulo 			   sel_reg_config_methods);
1509e28a4053SRui Paulo #endif /* CONFIG_WPS_ER */
1510e28a4053SRui Paulo }
1511e28a4053SRui Paulo 
1512e28a4053SRui Paulo 
wps_fix_config_methods(u16 config_methods)1513f05cddf9SRui Paulo static u16 wps_fix_config_methods(u16 config_methods)
1514f05cddf9SRui Paulo {
1515f05cddf9SRui Paulo 	if ((config_methods &
1516f05cddf9SRui Paulo 	     (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY |
1517f05cddf9SRui Paulo 	      WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) {
1518f05cddf9SRui Paulo 		wpa_printf(MSG_INFO, "WPS: Converting display to "
1519f05cddf9SRui Paulo 			   "virtual_display for WPS 2.0 compliance");
1520f05cddf9SRui Paulo 		config_methods |= WPS_CONFIG_VIRT_DISPLAY;
1521f05cddf9SRui Paulo 	}
1522f05cddf9SRui Paulo 	if ((config_methods &
1523f05cddf9SRui Paulo 	     (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON |
1524f05cddf9SRui Paulo 	      WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) {
1525f05cddf9SRui Paulo 		wpa_printf(MSG_INFO, "WPS: Converting push_button to "
1526f05cddf9SRui Paulo 			   "virtual_push_button for WPS 2.0 compliance");
1527f05cddf9SRui Paulo 		config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
1528f05cddf9SRui Paulo 	}
1529f05cddf9SRui Paulo 
1530f05cddf9SRui Paulo 	return config_methods;
1531f05cddf9SRui Paulo }
1532f05cddf9SRui Paulo 
1533f05cddf9SRui Paulo 
wpas_wps_set_uuid(struct wpa_supplicant * wpa_s,struct wps_context * wps)1534f05cddf9SRui Paulo static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
1535f05cddf9SRui Paulo 			      struct wps_context *wps)
1536f05cddf9SRui Paulo {
15375b9c547cSRui Paulo 	char buf[50];
15385b9c547cSRui Paulo 	const char *src;
15395b9c547cSRui Paulo 
1540f05cddf9SRui Paulo 	if (is_nil_uuid(wpa_s->conf->uuid)) {
1541f05cddf9SRui Paulo 		struct wpa_supplicant *first;
1542f05cddf9SRui Paulo 		first = wpa_s->global->ifaces;
1543f05cddf9SRui Paulo 		while (first && first->next)
1544f05cddf9SRui Paulo 			first = first->next;
1545f05cddf9SRui Paulo 		if (first && first != wpa_s) {
1546f05cddf9SRui Paulo 			if (wps != wpa_s->global->ifaces->wps)
1547f05cddf9SRui Paulo 				os_memcpy(wps->uuid,
1548f05cddf9SRui Paulo 					  wpa_s->global->ifaces->wps->uuid,
1549f05cddf9SRui Paulo 					  WPS_UUID_LEN);
15505b9c547cSRui Paulo 			src = "from the first interface";
155185732ac8SCy Schubert 		} else if (wpa_s->conf->auto_uuid == 1) {
155285732ac8SCy Schubert 			uuid_random(wps->uuid);
155385732ac8SCy Schubert 			src = "based on random data";
1554f05cddf9SRui Paulo 		} else {
1555f05cddf9SRui Paulo 			uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid);
15565b9c547cSRui Paulo 			src = "based on MAC address";
1557f05cddf9SRui Paulo 		}
1558f05cddf9SRui Paulo 	} else {
1559f05cddf9SRui Paulo 		os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
15605b9c547cSRui Paulo 		src = "based on configuration";
1561f05cddf9SRui Paulo 	}
15625b9c547cSRui Paulo 
15635b9c547cSRui Paulo 	uuid_bin2str(wps->uuid, buf, sizeof(buf));
15645b9c547cSRui Paulo 	wpa_dbg(wpa_s, MSG_DEBUG, "WPS: UUID %s: %s", src, buf);
1565f05cddf9SRui Paulo }
1566f05cddf9SRui Paulo 
1567f05cddf9SRui Paulo 
wpas_wps_set_vendor_ext_m1(struct wpa_supplicant * wpa_s,struct wps_context * wps)1568f05cddf9SRui Paulo static void wpas_wps_set_vendor_ext_m1(struct wpa_supplicant *wpa_s,
1569f05cddf9SRui Paulo 				       struct wps_context *wps)
1570f05cddf9SRui Paulo {
1571f05cddf9SRui Paulo 	wpabuf_free(wps->dev.vendor_ext_m1);
1572f05cddf9SRui Paulo 	wps->dev.vendor_ext_m1 = NULL;
1573f05cddf9SRui Paulo 
1574f05cddf9SRui Paulo 	if (wpa_s->conf->wps_vendor_ext_m1) {
1575f05cddf9SRui Paulo 		wps->dev.vendor_ext_m1 =
1576f05cddf9SRui Paulo 			wpabuf_dup(wpa_s->conf->wps_vendor_ext_m1);
1577f05cddf9SRui Paulo 		if (!wps->dev.vendor_ext_m1) {
1578f05cddf9SRui Paulo 			wpa_printf(MSG_ERROR, "WPS: Cannot "
1579f05cddf9SRui Paulo 				   "allocate memory for vendor_ext_m1");
1580f05cddf9SRui Paulo 		}
1581f05cddf9SRui Paulo 	}
1582f05cddf9SRui Paulo }
1583f05cddf9SRui Paulo 
1584f05cddf9SRui Paulo 
wpas_wps_init(struct wpa_supplicant * wpa_s)158539beb93cSSam Leffler int wpas_wps_init(struct wpa_supplicant *wpa_s)
158639beb93cSSam Leffler {
158739beb93cSSam Leffler 	struct wps_context *wps;
158839beb93cSSam Leffler 	struct wps_registrar_config rcfg;
1589f05cddf9SRui Paulo 	struct hostapd_hw_modes *modes;
1590f05cddf9SRui Paulo 	u16 m;
159139beb93cSSam Leffler 
159239beb93cSSam Leffler 	wps = os_zalloc(sizeof(*wps));
159339beb93cSSam Leffler 	if (wps == NULL)
159439beb93cSSam Leffler 		return -1;
159539beb93cSSam Leffler 
159639beb93cSSam Leffler 	wps->cred_cb = wpa_supplicant_wps_cred;
159739beb93cSSam Leffler 	wps->event_cb = wpa_supplicant_wps_event;
15985b9c547cSRui Paulo 	wps->rf_band_cb = wpa_supplicant_wps_rf_band;
159939beb93cSSam Leffler 	wps->cb_ctx = wpa_s;
160039beb93cSSam Leffler 
160139beb93cSSam Leffler 	wps->dev.device_name = wpa_s->conf->device_name;
160239beb93cSSam Leffler 	wps->dev.manufacturer = wpa_s->conf->manufacturer;
160339beb93cSSam Leffler 	wps->dev.model_name = wpa_s->conf->model_name;
160439beb93cSSam Leffler 	wps->dev.model_number = wpa_s->conf->model_number;
160539beb93cSSam Leffler 	wps->dev.serial_number = wpa_s->conf->serial_number;
1606e28a4053SRui Paulo 	wps->config_methods =
1607e28a4053SRui Paulo 		wps_config_methods_str2bin(wpa_s->conf->config_methods);
1608f05cddf9SRui Paulo 	if ((wps->config_methods & (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) ==
1609f05cddf9SRui Paulo 	    (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) {
1610f05cddf9SRui Paulo 		wpa_printf(MSG_ERROR, "WPS: Both Label and Display config "
1611f05cddf9SRui Paulo 			   "methods are not allowed at the same time");
161239beb93cSSam Leffler 		os_free(wps);
161339beb93cSSam Leffler 		return -1;
161439beb93cSSam Leffler 	}
1615f05cddf9SRui Paulo 	wps->config_methods = wps_fix_config_methods(wps->config_methods);
1616f05cddf9SRui Paulo 	wps->dev.config_methods = wps->config_methods;
1617f05cddf9SRui Paulo 	os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type,
1618f05cddf9SRui Paulo 		  WPS_DEV_TYPE_LEN);
1619f05cddf9SRui Paulo 
1620f05cddf9SRui Paulo 	wps->dev.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
1621f05cddf9SRui Paulo 	os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type,
1622f05cddf9SRui Paulo 		  WPS_DEV_TYPE_LEN * wps->dev.num_sec_dev_types);
1623f05cddf9SRui Paulo 
1624f05cddf9SRui Paulo 	wpas_wps_set_vendor_ext_m1(wpa_s, wps);
1625f05cddf9SRui Paulo 
162639beb93cSSam Leffler 	wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
1627f05cddf9SRui Paulo 	modes = wpa_s->hw.modes;
1628f05cddf9SRui Paulo 	if (modes) {
1629f05cddf9SRui Paulo 		for (m = 0; m < wpa_s->hw.num_modes; m++) {
1630f05cddf9SRui Paulo 			if (modes[m].mode == HOSTAPD_MODE_IEEE80211B ||
1631f05cddf9SRui Paulo 			    modes[m].mode == HOSTAPD_MODE_IEEE80211G)
1632f05cddf9SRui Paulo 				wps->dev.rf_bands |= WPS_RF_24GHZ;
1633f05cddf9SRui Paulo 			else if (modes[m].mode == HOSTAPD_MODE_IEEE80211A)
1634f05cddf9SRui Paulo 				wps->dev.rf_bands |= WPS_RF_50GHZ;
1635325151a3SRui Paulo 			else if (modes[m].mode == HOSTAPD_MODE_IEEE80211AD)
1636325151a3SRui Paulo 				wps->dev.rf_bands |= WPS_RF_60GHZ;
1637f05cddf9SRui Paulo 		}
1638f05cddf9SRui Paulo 	}
1639f05cddf9SRui Paulo 	if (wps->dev.rf_bands == 0) {
1640f05cddf9SRui Paulo 		/*
1641f05cddf9SRui Paulo 		 * Default to claiming support for both bands if the driver
1642f05cddf9SRui Paulo 		 * does not provide support for fetching supported bands.
1643f05cddf9SRui Paulo 		 */
1644f05cddf9SRui Paulo 		wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ;
1645f05cddf9SRui Paulo 	}
164639beb93cSSam Leffler 	os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
1647f05cddf9SRui Paulo 	wpas_wps_set_uuid(wpa_s, wps);
164839beb93cSSam Leffler 
1649c1d255d3SCy Schubert #ifdef CONFIG_NO_TKIP
1650c1d255d3SCy Schubert 	wps->auth_types = WPS_AUTH_WPA2PSK;
1651c1d255d3SCy Schubert 	wps->encr_types = WPS_ENCR_AES;
1652c1d255d3SCy Schubert #else /* CONFIG_NO_TKIP */
165339beb93cSSam Leffler 	wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
165439beb93cSSam Leffler 	wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
1655c1d255d3SCy Schubert #endif /* CONFIG_NO_TKIP */
165639beb93cSSam Leffler 
165739beb93cSSam Leffler 	os_memset(&rcfg, 0, sizeof(rcfg));
165839beb93cSSam Leffler 	rcfg.new_psk_cb = wpas_wps_new_psk_cb;
165939beb93cSSam Leffler 	rcfg.pin_needed_cb = wpas_wps_pin_needed_cb;
1660e28a4053SRui Paulo 	rcfg.set_sel_reg_cb = wpas_wps_set_sel_reg_cb;
166139beb93cSSam Leffler 	rcfg.cb_ctx = wpa_s;
166239beb93cSSam Leffler 
166339beb93cSSam Leffler 	wps->registrar = wps_registrar_init(wps, &rcfg);
166439beb93cSSam Leffler 	if (wps->registrar == NULL) {
166539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to initialize WPS Registrar");
166639beb93cSSam Leffler 		os_free(wps);
166739beb93cSSam Leffler 		return -1;
166839beb93cSSam Leffler 	}
166939beb93cSSam Leffler 
167039beb93cSSam Leffler 	wpa_s->wps = wps;
167139beb93cSSam Leffler 
167239beb93cSSam Leffler 	return 0;
167339beb93cSSam Leffler }
167439beb93cSSam Leffler 
167539beb93cSSam Leffler 
16765b9c547cSRui Paulo #ifdef CONFIG_WPS_ER
wpas_wps_nfc_clear(struct wps_context * wps)16775b9c547cSRui Paulo static void wpas_wps_nfc_clear(struct wps_context *wps)
16785b9c547cSRui Paulo {
16795b9c547cSRui Paulo 	wps->ap_nfc_dev_pw_id = 0;
16805b9c547cSRui Paulo 	wpabuf_free(wps->ap_nfc_dh_pubkey);
16815b9c547cSRui Paulo 	wps->ap_nfc_dh_pubkey = NULL;
16825b9c547cSRui Paulo 	wpabuf_free(wps->ap_nfc_dh_privkey);
16835b9c547cSRui Paulo 	wps->ap_nfc_dh_privkey = NULL;
16845b9c547cSRui Paulo 	wpabuf_free(wps->ap_nfc_dev_pw);
16855b9c547cSRui Paulo 	wps->ap_nfc_dev_pw = NULL;
16865b9c547cSRui Paulo }
16875b9c547cSRui Paulo #endif /* CONFIG_WPS_ER */
16885b9c547cSRui Paulo 
16895b9c547cSRui Paulo 
wpas_wps_deinit(struct wpa_supplicant * wpa_s)169039beb93cSSam Leffler void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
169139beb93cSSam Leffler {
16925b9c547cSRui Paulo 	wpas_wps_assoc_with_cred_cancel(wpa_s);
169339beb93cSSam Leffler 	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
16945b9c547cSRui Paulo 	eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
1695f05cddf9SRui Paulo 	eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
1696f05cddf9SRui Paulo 	wpas_wps_clear_ap_info(wpa_s);
169739beb93cSSam Leffler 
16985b9c547cSRui Paulo #ifdef CONFIG_P2P
16995b9c547cSRui Paulo 	eloop_cancel_timeout(wpas_p2p_pbc_overlap_cb, wpa_s, NULL);
17005b9c547cSRui Paulo #endif /* CONFIG_P2P */
17015b9c547cSRui Paulo 
170239beb93cSSam Leffler 	if (wpa_s->wps == NULL)
170339beb93cSSam Leffler 		return;
170439beb93cSSam Leffler 
1705e28a4053SRui Paulo #ifdef CONFIG_WPS_ER
1706e28a4053SRui Paulo 	wps_er_deinit(wpa_s->wps_er, NULL, NULL);
1707e28a4053SRui Paulo 	wpa_s->wps_er = NULL;
17085b9c547cSRui Paulo 	wpas_wps_nfc_clear(wpa_s->wps);
1709e28a4053SRui Paulo #endif /* CONFIG_WPS_ER */
1710e28a4053SRui Paulo 
171139beb93cSSam Leffler 	wps_registrar_deinit(wpa_s->wps->registrar);
1712e28a4053SRui Paulo 	wpabuf_free(wpa_s->wps->dh_pubkey);
1713e28a4053SRui Paulo 	wpabuf_free(wpa_s->wps->dh_privkey);
1714f05cddf9SRui Paulo 	wpabuf_free(wpa_s->wps->dev.vendor_ext_m1);
171539beb93cSSam Leffler 	os_free(wpa_s->wps->network_key);
171639beb93cSSam Leffler 	os_free(wpa_s->wps);
171739beb93cSSam Leffler 	wpa_s->wps = NULL;
171839beb93cSSam Leffler }
171939beb93cSSam Leffler 
172039beb93cSSam Leffler 
wpas_wps_ssid_bss_match(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,struct wpa_bss * bss)172139beb93cSSam Leffler int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
1722f05cddf9SRui Paulo 			    struct wpa_ssid *ssid, struct wpa_bss *bss)
172339beb93cSSam Leffler {
172439beb93cSSam Leffler 	struct wpabuf *wps_ie;
172539beb93cSSam Leffler 
172639beb93cSSam Leffler 	if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
172739beb93cSSam Leffler 		return -1;
172839beb93cSSam Leffler 
1729*a90b9d01SCy Schubert 	wps_ie = wpas_wps_get_wps_ie(bss);
173039beb93cSSam Leffler 	if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
173139beb93cSSam Leffler 		if (!wps_ie) {
173239beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "   skip - non-WPS AP");
173339beb93cSSam Leffler 			return 0;
173439beb93cSSam Leffler 		}
173539beb93cSSam Leffler 
173639beb93cSSam Leffler 		if (!wps_is_selected_pbc_registrar(wps_ie)) {
173739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "   skip - WPS AP "
173839beb93cSSam Leffler 				   "without active PBC Registrar");
173939beb93cSSam Leffler 			wpabuf_free(wps_ie);
174039beb93cSSam Leffler 			return 0;
174139beb93cSSam Leffler 		}
174239beb93cSSam Leffler 
174339beb93cSSam Leffler 		/* TODO: overlap detection */
174439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   selected based on WPS IE "
174539beb93cSSam Leffler 			   "(Active PBC)");
174639beb93cSSam Leffler 		wpabuf_free(wps_ie);
174739beb93cSSam Leffler 		return 1;
174839beb93cSSam Leffler 	}
174939beb93cSSam Leffler 
175039beb93cSSam Leffler 	if (eap_is_wps_pin_enrollee(&ssid->eap)) {
175139beb93cSSam Leffler 		if (!wps_ie) {
175239beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "   skip - non-WPS AP");
175339beb93cSSam Leffler 			return 0;
175439beb93cSSam Leffler 		}
175539beb93cSSam Leffler 
175639beb93cSSam Leffler 		/*
1757f05cddf9SRui Paulo 		 * Start with WPS APs that advertise our address as an
1758f05cddf9SRui Paulo 		 * authorized MAC (v2.0) or active PIN Registrar (v1.0) and
1759f05cddf9SRui Paulo 		 * allow any WPS AP after couple of scans since some APs do not
1760f05cddf9SRui Paulo 		 * set Selected Registrar attribute properly when using
1761f05cddf9SRui Paulo 		 * external Registrar.
176239beb93cSSam Leffler 		 */
1763f05cddf9SRui Paulo 		if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
1764325151a3SRui Paulo 			struct os_reltime age;
1765325151a3SRui Paulo 
1766325151a3SRui Paulo 			os_reltime_age(&wpa_s->wps_pin_start_time, &age);
1767325151a3SRui Paulo 
1768325151a3SRui Paulo 			if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG ||
1769325151a3SRui Paulo 			    age.sec < WPS_PIN_TIME_IGNORE_SEL_REG) {
1770325151a3SRui Paulo 				wpa_printf(MSG_DEBUG,
1771325151a3SRui Paulo 					   "   skip - WPS AP without active PIN Registrar (scan_runs=%d age=%d)",
1772325151a3SRui Paulo 					   wpa_s->scan_runs, (int) age.sec);
177339beb93cSSam Leffler 				wpabuf_free(wps_ie);
177439beb93cSSam Leffler 				return 0;
177539beb93cSSam Leffler 			}
177639beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "   selected based on WPS IE");
177739beb93cSSam Leffler 		} else {
177839beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "   selected based on WPS IE "
1779f05cddf9SRui Paulo 				   "(Authorized MAC or Active PIN)");
178039beb93cSSam Leffler 		}
178139beb93cSSam Leffler 		wpabuf_free(wps_ie);
178239beb93cSSam Leffler 		return 1;
178339beb93cSSam Leffler 	}
178439beb93cSSam Leffler 
178539beb93cSSam Leffler 	if (wps_ie) {
178639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   selected based on WPS IE");
178739beb93cSSam Leffler 		wpabuf_free(wps_ie);
178839beb93cSSam Leffler 		return 1;
178939beb93cSSam Leffler 	}
179039beb93cSSam Leffler 
179139beb93cSSam Leffler 	return -1;
179239beb93cSSam Leffler }
179339beb93cSSam Leffler 
179439beb93cSSam Leffler 
wpas_wps_ssid_wildcard_ok(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,struct wpa_bss * bss)179539beb93cSSam Leffler int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
179639beb93cSSam Leffler 			      struct wpa_ssid *ssid,
1797f05cddf9SRui Paulo 			      struct wpa_bss *bss)
179839beb93cSSam Leffler {
179939beb93cSSam Leffler 	struct wpabuf *wps_ie = NULL;
180039beb93cSSam Leffler 	int ret = 0;
180139beb93cSSam Leffler 
180239beb93cSSam Leffler 	if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
1803*a90b9d01SCy Schubert 		wps_ie = wpas_wps_get_wps_ie(bss);
180439beb93cSSam Leffler 		if (wps_ie && wps_is_selected_pbc_registrar(wps_ie)) {
180539beb93cSSam Leffler 			/* allow wildcard SSID for WPS PBC */
180639beb93cSSam Leffler 			ret = 1;
180739beb93cSSam Leffler 		}
180839beb93cSSam Leffler 	} else if (eap_is_wps_pin_enrollee(&ssid->eap)) {
1809*a90b9d01SCy Schubert 		wps_ie = wpas_wps_get_wps_ie(bss);
181039beb93cSSam Leffler 		if (wps_ie &&
1811f05cddf9SRui Paulo 		    (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1) ||
181239beb93cSSam Leffler 		     wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) {
181339beb93cSSam Leffler 			/* allow wildcard SSID for WPS PIN */
181439beb93cSSam Leffler 			ret = 1;
181539beb93cSSam Leffler 		}
181639beb93cSSam Leffler 	}
181739beb93cSSam Leffler 
181839beb93cSSam Leffler 	if (!ret && ssid->bssid_set &&
1819*a90b9d01SCy Schubert 	    ether_addr_equal(ssid->bssid, bss->bssid)) {
182039beb93cSSam Leffler 		/* allow wildcard SSID due to hardcoded BSSID match */
182139beb93cSSam Leffler 		ret = 1;
182239beb93cSSam Leffler 	}
182339beb93cSSam Leffler 
1824f05cddf9SRui Paulo #ifdef CONFIG_WPS_STRICT
1825f05cddf9SRui Paulo 	if (wps_ie) {
1826f05cddf9SRui Paulo 		if (wps_validate_beacon_probe_resp(wps_ie, bss->beacon_ie_len >
1827f05cddf9SRui Paulo 						   0, bss->bssid) < 0)
1828f05cddf9SRui Paulo 			ret = 0;
1829f05cddf9SRui Paulo 		if (bss->beacon_ie_len) {
1830f05cddf9SRui Paulo 			struct wpabuf *bcn_wps;
1831f05cddf9SRui Paulo 			bcn_wps = wpa_bss_get_vendor_ie_multi_beacon(
1832f05cddf9SRui Paulo 				bss, WPS_IE_VENDOR_TYPE);
1833f05cddf9SRui Paulo 			if (bcn_wps == NULL) {
1834f05cddf9SRui Paulo 				wpa_printf(MSG_DEBUG, "WPS: Mandatory WPS IE "
1835f05cddf9SRui Paulo 					   "missing from AP Beacon");
1836f05cddf9SRui Paulo 				ret = 0;
1837f05cddf9SRui Paulo 			} else {
1838f05cddf9SRui Paulo 				if (wps_validate_beacon(wps_ie) < 0)
1839f05cddf9SRui Paulo 					ret = 0;
1840f05cddf9SRui Paulo 				wpabuf_free(bcn_wps);
1841f05cddf9SRui Paulo 			}
1842f05cddf9SRui Paulo 		}
1843f05cddf9SRui Paulo 	}
1844f05cddf9SRui Paulo #endif /* CONFIG_WPS_STRICT */
1845f05cddf9SRui Paulo 
184639beb93cSSam Leffler 	wpabuf_free(wps_ie);
184739beb93cSSam Leffler 
184839beb93cSSam Leffler 	return ret;
184939beb93cSSam Leffler }
185039beb93cSSam Leffler 
185139beb93cSSam Leffler 
wpas_wps_is_pbc_overlap(struct wps_ap_info * ap,struct wpa_bss * selected,struct wpa_ssid * ssid,const u8 * sel_uuid)1852*a90b9d01SCy Schubert static bool wpas_wps_is_pbc_overlap(struct wps_ap_info *ap,
1853*a90b9d01SCy Schubert 				    struct wpa_bss *selected,
1854*a90b9d01SCy Schubert 				    struct wpa_ssid *ssid,
1855*a90b9d01SCy Schubert 				    const u8 *sel_uuid)
1856*a90b9d01SCy Schubert {
1857*a90b9d01SCy Schubert 	if (!ap->pbc_active ||
1858*a90b9d01SCy Schubert 	    ether_addr_equal(selected->bssid, ap->bssid))
1859*a90b9d01SCy Schubert 		return false;
1860*a90b9d01SCy Schubert 
1861*a90b9d01SCy Schubert 	if (!is_zero_ether_addr(ssid->bssid) &&
1862*a90b9d01SCy Schubert 	    !ether_addr_equal(ap->bssid, ssid->bssid)) {
1863*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "WPS: Ignore another BSS " MACSTR
1864*a90b9d01SCy Schubert 			   " in active PBC mode due to local BSSID limitation",
1865*a90b9d01SCy Schubert 			   MAC2STR(ap->bssid));
1866*a90b9d01SCy Schubert 		return 0;
1867*a90b9d01SCy Schubert 	}
1868*a90b9d01SCy Schubert 
1869*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: " MACSTR,
1870*a90b9d01SCy Schubert 		   MAC2STR(ap->bssid));
1871*a90b9d01SCy Schubert 	wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
1872*a90b9d01SCy Schubert 		    ap->uuid, UUID_LEN);
1873*a90b9d01SCy Schubert 	if (!sel_uuid || os_memcmp(sel_uuid, ap->uuid, UUID_LEN) != 0)
1874*a90b9d01SCy Schubert 		return true;
1875*a90b9d01SCy Schubert 
1876*a90b9d01SCy Schubert 	/* TODO: verify that this is reasonable dual-band situation */
1877*a90b9d01SCy Schubert 
1878*a90b9d01SCy Schubert 	return false;
1879*a90b9d01SCy Schubert }
1880*a90b9d01SCy Schubert 
1881*a90b9d01SCy Schubert 
wpas_wps_scan_pbc_overlap(struct wpa_supplicant * wpa_s,struct wpa_bss * selected,struct wpa_ssid * ssid)188239beb93cSSam Leffler int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
1883e28a4053SRui Paulo 			      struct wpa_bss *selected, struct wpa_ssid *ssid)
188439beb93cSSam Leffler {
1885*a90b9d01SCy Schubert 	struct wpa_supplicant *iface;
1886325151a3SRui Paulo 	const u8 *sel_uuid;
188739beb93cSSam Leffler 	struct wpabuf *wps_ie;
188839beb93cSSam Leffler 	int ret = 0;
1889325151a3SRui Paulo 	size_t i;
189039beb93cSSam Leffler 
189139beb93cSSam Leffler 	if (!eap_is_wps_pbc_enrollee(&ssid->eap))
189239beb93cSSam Leffler 		return 0;
189339beb93cSSam Leffler 
1894f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "WPS: Check whether PBC session overlap is "
1895f05cddf9SRui Paulo 		   "present in scan results; selected BSSID " MACSTR,
1896f05cddf9SRui Paulo 		   MAC2STR(selected->bssid));
1897c1d255d3SCy Schubert 	if (!is_zero_ether_addr(ssid->bssid))
1898c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1899c1d255d3SCy Schubert 			   "WPS: Network profile limited to accept only a single BSSID " MACSTR,
1900c1d255d3SCy Schubert 			   MAC2STR(ssid->bssid));
1901f05cddf9SRui Paulo 
190239beb93cSSam Leffler 	/* Make sure that only one AP is in active PBC mode */
1903e28a4053SRui Paulo 	wps_ie = wpa_bss_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE);
1904f05cddf9SRui Paulo 	if (wps_ie) {
190539beb93cSSam Leffler 		sel_uuid = wps_get_uuid_e(wps_ie);
1906f05cddf9SRui Paulo 		wpa_hexdump(MSG_DEBUG, "WPS: UUID of the selected BSS",
1907f05cddf9SRui Paulo 			    sel_uuid, UUID_LEN);
1908f05cddf9SRui Paulo 	} else {
1909f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Selected BSS does not include "
1910f05cddf9SRui Paulo 			   "WPS IE?!");
191139beb93cSSam Leffler 		sel_uuid = NULL;
1912f05cddf9SRui Paulo 	}
191339beb93cSSam Leffler 
1914*a90b9d01SCy Schubert 	for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
1915*a90b9d01SCy Schubert 		for (i = 0; i < iface->num_wps_ap; i++) {
1916*a90b9d01SCy Schubert 			struct wps_ap_info *ap = &iface->wps_ap[i];
1917325151a3SRui Paulo 
1918*a90b9d01SCy Schubert 			if (wpas_wps_is_pbc_overlap(ap, selected, ssid,
1919*a90b9d01SCy Schubert 						    sel_uuid)) {
192039beb93cSSam Leffler 				ret = 1; /* PBC overlap */
1921*a90b9d01SCy Schubert 				wpa_msg(iface, MSG_INFO,
1922*a90b9d01SCy Schubert 					"WPS: PBC overlap detected: "
1923f05cddf9SRui Paulo 					MACSTR " and " MACSTR,
1924f05cddf9SRui Paulo 					MAC2STR(selected->bssid),
1925325151a3SRui Paulo 					MAC2STR(ap->bssid));
192639beb93cSSam Leffler 				break;
192739beb93cSSam Leffler 			}
1928*a90b9d01SCy Schubert 		}
192939beb93cSSam Leffler 	}
193039beb93cSSam Leffler 
193139beb93cSSam Leffler 	wpabuf_free(wps_ie);
193239beb93cSSam Leffler 
193339beb93cSSam Leffler 	return ret;
193439beb93cSSam Leffler }
193539beb93cSSam Leffler 
193639beb93cSSam Leffler 
wpas_wps_notify_scan_results(struct wpa_supplicant * wpa_s)193739beb93cSSam Leffler void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s)
193839beb93cSSam Leffler {
1939e28a4053SRui Paulo 	struct wpa_bss *bss;
1940f05cddf9SRui Paulo 	unsigned int pbc = 0, auth = 0, pin = 0, wps = 0;
194139beb93cSSam Leffler 
194239beb93cSSam Leffler 	if (wpa_s->disconnected || wpa_s->wpa_state >= WPA_ASSOCIATED)
194339beb93cSSam Leffler 		return;
194439beb93cSSam Leffler 
1945e28a4053SRui Paulo 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
194639beb93cSSam Leffler 		struct wpabuf *ie;
1947*a90b9d01SCy Schubert 
1948*a90b9d01SCy Schubert 		ie = wpas_wps_get_wps_ie(bss);
194939beb93cSSam Leffler 		if (!ie)
195039beb93cSSam Leffler 			continue;
195139beb93cSSam Leffler 		if (wps_is_selected_pbc_registrar(ie))
1952f05cddf9SRui Paulo 			pbc++;
1953f05cddf9SRui Paulo 		else if (wps_is_addr_authorized(ie, wpa_s->own_addr, 0))
1954f05cddf9SRui Paulo 			auth++;
195539beb93cSSam Leffler 		else if (wps_is_selected_pin_registrar(ie))
1956f05cddf9SRui Paulo 			pin++;
195739beb93cSSam Leffler 		else
1958f05cddf9SRui Paulo 			wps++;
195939beb93cSSam Leffler 		wpabuf_free(ie);
196039beb93cSSam Leffler 	}
1961f05cddf9SRui Paulo 
1962f05cddf9SRui Paulo 	if (pbc)
1963f05cddf9SRui Paulo 		wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PBC);
1964f05cddf9SRui Paulo 	else if (auth)
1965f05cddf9SRui Paulo 		wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_AUTH);
1966f05cddf9SRui Paulo 	else if (pin)
1967f05cddf9SRui Paulo 		wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PIN);
1968f05cddf9SRui Paulo 	else if (wps)
1969f05cddf9SRui Paulo 		wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE);
197039beb93cSSam Leffler }
197139beb93cSSam Leffler 
197239beb93cSSam Leffler 
wpas_wps_searching(struct wpa_supplicant * wpa_s)197339beb93cSSam Leffler int wpas_wps_searching(struct wpa_supplicant *wpa_s)
197439beb93cSSam Leffler {
197539beb93cSSam Leffler 	struct wpa_ssid *ssid;
197639beb93cSSam Leffler 
197739beb93cSSam Leffler 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
197839beb93cSSam Leffler 		if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && !ssid->disabled)
197939beb93cSSam Leffler 			return 1;
198039beb93cSSam Leffler 	}
198139beb93cSSam Leffler 
198239beb93cSSam Leffler 	return 0;
198339beb93cSSam Leffler }
1984e28a4053SRui Paulo 
1985e28a4053SRui Paulo 
wpas_wps_scan_result_text(const u8 * ies,size_t ies_len,char * buf,char * end)1986e28a4053SRui Paulo int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
1987e28a4053SRui Paulo 			      char *end)
1988e28a4053SRui Paulo {
1989e28a4053SRui Paulo 	struct wpabuf *wps_ie;
1990e28a4053SRui Paulo 	int ret;
1991e28a4053SRui Paulo 
1992e28a4053SRui Paulo 	wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, WPS_DEV_OUI_WFA);
1993e28a4053SRui Paulo 	if (wps_ie == NULL)
1994e28a4053SRui Paulo 		return 0;
1995e28a4053SRui Paulo 
1996e28a4053SRui Paulo 	ret = wps_attr_text(wps_ie, buf, end);
1997e28a4053SRui Paulo 	wpabuf_free(wps_ie);
1998e28a4053SRui Paulo 	return ret;
1999e28a4053SRui Paulo }
2000e28a4053SRui Paulo 
2001e28a4053SRui Paulo 
wpas_wps_er_start(struct wpa_supplicant * wpa_s,const char * filter)2002f05cddf9SRui Paulo int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter)
2003e28a4053SRui Paulo {
2004e28a4053SRui Paulo #ifdef CONFIG_WPS_ER
2005e28a4053SRui Paulo 	if (wpa_s->wps_er) {
2006e28a4053SRui Paulo 		wps_er_refresh(wpa_s->wps_er);
2007e28a4053SRui Paulo 		return 0;
2008e28a4053SRui Paulo 	}
2009f05cddf9SRui Paulo 	wpa_s->wps_er = wps_er_init(wpa_s->wps, wpa_s->ifname, filter);
2010e28a4053SRui Paulo 	if (wpa_s->wps_er == NULL)
2011e28a4053SRui Paulo 		return -1;
2012e28a4053SRui Paulo 	return 0;
2013e28a4053SRui Paulo #else /* CONFIG_WPS_ER */
2014e28a4053SRui Paulo 	return 0;
2015e28a4053SRui Paulo #endif /* CONFIG_WPS_ER */
2016e28a4053SRui Paulo }
2017e28a4053SRui Paulo 
2018e28a4053SRui Paulo 
wpas_wps_er_stop(struct wpa_supplicant * wpa_s)20195b9c547cSRui Paulo void wpas_wps_er_stop(struct wpa_supplicant *wpa_s)
2020e28a4053SRui Paulo {
2021e28a4053SRui Paulo #ifdef CONFIG_WPS_ER
2022e28a4053SRui Paulo 	wps_er_deinit(wpa_s->wps_er, NULL, NULL);
2023e28a4053SRui Paulo 	wpa_s->wps_er = NULL;
2024e28a4053SRui Paulo #endif /* CONFIG_WPS_ER */
2025e28a4053SRui Paulo }
2026e28a4053SRui Paulo 
2027e28a4053SRui Paulo 
2028e28a4053SRui Paulo #ifdef CONFIG_WPS_ER
wpas_wps_er_add_pin(struct wpa_supplicant * wpa_s,const u8 * addr,const char * uuid,const char * pin)2029f05cddf9SRui Paulo int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr,
2030f05cddf9SRui Paulo 			const char *uuid, const char *pin)
2031e28a4053SRui Paulo {
2032e28a4053SRui Paulo 	u8 u[UUID_LEN];
20335b9c547cSRui Paulo 	const u8 *use_uuid = NULL;
20345b9c547cSRui Paulo 	u8 addr_buf[ETH_ALEN];
2035e28a4053SRui Paulo 
20365b9c547cSRui Paulo 	if (os_strcmp(uuid, "any") == 0) {
20375b9c547cSRui Paulo 	} else if (uuid_str2bin(uuid, u) == 0) {
20385b9c547cSRui Paulo 		use_uuid = u;
20395b9c547cSRui Paulo 	} else if (hwaddr_aton(uuid, addr_buf) == 0) {
20405b9c547cSRui Paulo 		use_uuid = wps_er_get_sta_uuid(wpa_s->wps_er, addr_buf);
20415b9c547cSRui Paulo 		if (use_uuid == NULL)
20425b9c547cSRui Paulo 			return -1;
20435b9c547cSRui Paulo 	} else
2044e28a4053SRui Paulo 		return -1;
2045f05cddf9SRui Paulo 	return wps_registrar_add_pin(wpa_s->wps->registrar, addr,
20465b9c547cSRui Paulo 				     use_uuid,
2047e28a4053SRui Paulo 				     (const u8 *) pin, os_strlen(pin), 300);
2048e28a4053SRui Paulo }
2049e28a4053SRui Paulo 
2050e28a4053SRui Paulo 
wpas_wps_er_pbc(struct wpa_supplicant * wpa_s,const char * uuid)2051e28a4053SRui Paulo int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid)
2052e28a4053SRui Paulo {
20535b9c547cSRui Paulo 	u8 u[UUID_LEN], *use_uuid = NULL;
20545b9c547cSRui Paulo 	u8 addr[ETH_ALEN], *use_addr = NULL;
2055e28a4053SRui Paulo 
20565b9c547cSRui Paulo 	if (uuid_str2bin(uuid, u) == 0)
20575b9c547cSRui Paulo 		use_uuid = u;
20585b9c547cSRui Paulo 	else if (hwaddr_aton(uuid, addr) == 0)
20595b9c547cSRui Paulo 		use_addr = addr;
20605b9c547cSRui Paulo 	else
2061e28a4053SRui Paulo 		return -1;
20625b9c547cSRui Paulo 	return wps_er_pbc(wpa_s->wps_er, use_uuid, use_addr);
2063e28a4053SRui Paulo }
2064e28a4053SRui Paulo 
2065e28a4053SRui Paulo 
wpas_wps_er_learn(struct wpa_supplicant * wpa_s,const char * uuid,const char * pin)2066e28a4053SRui Paulo int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
2067e28a4053SRui Paulo 		      const char *pin)
2068e28a4053SRui Paulo {
20695b9c547cSRui Paulo 	u8 u[UUID_LEN], *use_uuid = NULL;
20705b9c547cSRui Paulo 	u8 addr[ETH_ALEN], *use_addr = NULL;
2071e28a4053SRui Paulo 
20725b9c547cSRui Paulo 	if (uuid_str2bin(uuid, u) == 0)
20735b9c547cSRui Paulo 		use_uuid = u;
20745b9c547cSRui Paulo 	else if (hwaddr_aton(uuid, addr) == 0)
20755b9c547cSRui Paulo 		use_addr = addr;
20765b9c547cSRui Paulo 	else
2077e28a4053SRui Paulo 		return -1;
20785b9c547cSRui Paulo 
20795b9c547cSRui Paulo 	return wps_er_learn(wpa_s->wps_er, use_uuid, use_addr, (const u8 *) pin,
2080e28a4053SRui Paulo 			    os_strlen(pin));
2081e28a4053SRui Paulo }
2082e28a4053SRui Paulo 
2083e28a4053SRui Paulo 
wpas_wps_network_to_cred(struct wpa_ssid * ssid,struct wps_credential * cred)20845b9c547cSRui Paulo static int wpas_wps_network_to_cred(struct wpa_ssid *ssid,
20855b9c547cSRui Paulo 				    struct wps_credential *cred)
20865b9c547cSRui Paulo {
20875b9c547cSRui Paulo 	os_memset(cred, 0, sizeof(*cred));
2088325151a3SRui Paulo 	if (ssid->ssid_len > SSID_MAX_LEN)
20895b9c547cSRui Paulo 		return -1;
20905b9c547cSRui Paulo 	os_memcpy(cred->ssid, ssid->ssid, ssid->ssid_len);
20915b9c547cSRui Paulo 	cred->ssid_len = ssid->ssid_len;
20925b9c547cSRui Paulo 	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
20935b9c547cSRui Paulo 		cred->auth_type = (ssid->proto & WPA_PROTO_RSN) ?
20945b9c547cSRui Paulo 			WPS_AUTH_WPA2PSK : WPS_AUTH_WPAPSK;
20955b9c547cSRui Paulo 		if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
20965b9c547cSRui Paulo 			cred->encr_type = WPS_ENCR_AES;
20975b9c547cSRui Paulo 		else
20985b9c547cSRui Paulo 			cred->encr_type = WPS_ENCR_TKIP;
20995b9c547cSRui Paulo 		if (ssid->passphrase) {
21005b9c547cSRui Paulo 			cred->key_len = os_strlen(ssid->passphrase);
21015b9c547cSRui Paulo 			if (cred->key_len >= 64)
21025b9c547cSRui Paulo 				return -1;
21035b9c547cSRui Paulo 			os_memcpy(cred->key, ssid->passphrase, cred->key_len);
21045b9c547cSRui Paulo 		} else if (ssid->psk_set) {
21055b9c547cSRui Paulo 			cred->key_len = 32;
21065b9c547cSRui Paulo 			os_memcpy(cred->key, ssid->psk, 32);
21075b9c547cSRui Paulo 		} else
21085b9c547cSRui Paulo 			return -1;
21095b9c547cSRui Paulo 	} else {
21105b9c547cSRui Paulo 		cred->auth_type = WPS_AUTH_OPEN;
21115b9c547cSRui Paulo 		cred->encr_type = WPS_ENCR_NONE;
21125b9c547cSRui Paulo 	}
21135b9c547cSRui Paulo 
21145b9c547cSRui Paulo 	return 0;
21155b9c547cSRui Paulo }
21165b9c547cSRui Paulo 
21175b9c547cSRui Paulo 
wpas_wps_er_set_config(struct wpa_supplicant * wpa_s,const char * uuid,int id)2118f05cddf9SRui Paulo int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
2119f05cddf9SRui Paulo 			   int id)
2120f05cddf9SRui Paulo {
21215b9c547cSRui Paulo 	u8 u[UUID_LEN], *use_uuid = NULL;
21225b9c547cSRui Paulo 	u8 addr[ETH_ALEN], *use_addr = NULL;
2123f05cddf9SRui Paulo 	struct wpa_ssid *ssid;
2124f05cddf9SRui Paulo 	struct wps_credential cred;
21255b9c547cSRui Paulo 	int ret;
2126f05cddf9SRui Paulo 
21275b9c547cSRui Paulo 	if (uuid_str2bin(uuid, u) == 0)
21285b9c547cSRui Paulo 		use_uuid = u;
21295b9c547cSRui Paulo 	else if (hwaddr_aton(uuid, addr) == 0)
21305b9c547cSRui Paulo 		use_addr = addr;
21315b9c547cSRui Paulo 	else
2132f05cddf9SRui Paulo 		return -1;
2133f05cddf9SRui Paulo 	ssid = wpa_config_get_network(wpa_s->conf, id);
2134f05cddf9SRui Paulo 	if (ssid == NULL || ssid->ssid == NULL)
2135f05cddf9SRui Paulo 		return -1;
2136f05cddf9SRui Paulo 
21375b9c547cSRui Paulo 	if (wpas_wps_network_to_cred(ssid, &cred) < 0)
21385b9c547cSRui Paulo 		return -1;
21395b9c547cSRui Paulo 	ret = wps_er_set_config(wpa_s->wps_er, use_uuid, use_addr, &cred);
2140f05cddf9SRui Paulo 	os_memset(&cred, 0, sizeof(cred));
21415b9c547cSRui Paulo 	return ret;
2142f05cddf9SRui Paulo }
2143f05cddf9SRui Paulo 
2144f05cddf9SRui Paulo 
wpas_wps_er_config(struct wpa_supplicant * wpa_s,const char * uuid,const char * pin,struct wps_new_ap_settings * settings)2145f05cddf9SRui Paulo int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
2146f05cddf9SRui Paulo 		       const char *pin, struct wps_new_ap_settings *settings)
2147f05cddf9SRui Paulo {
21485b9c547cSRui Paulo 	u8 u[UUID_LEN], *use_uuid = NULL;
21495b9c547cSRui Paulo 	u8 addr[ETH_ALEN], *use_addr = NULL;
2150f05cddf9SRui Paulo 	struct wps_credential cred;
2151f05cddf9SRui Paulo 	size_t len;
2152f05cddf9SRui Paulo 
21535b9c547cSRui Paulo 	if (uuid_str2bin(uuid, u) == 0)
21545b9c547cSRui Paulo 		use_uuid = u;
21555b9c547cSRui Paulo 	else if (hwaddr_aton(uuid, addr) == 0)
21565b9c547cSRui Paulo 		use_addr = addr;
21575b9c547cSRui Paulo 	else
2158f05cddf9SRui Paulo 		return -1;
2159f05cddf9SRui Paulo 	if (settings->ssid_hex == NULL || settings->auth == NULL ||
2160f05cddf9SRui Paulo 	    settings->encr == NULL || settings->key_hex == NULL)
2161f05cddf9SRui Paulo 		return -1;
2162f05cddf9SRui Paulo 
2163f05cddf9SRui Paulo 	os_memset(&cred, 0, sizeof(cred));
2164f05cddf9SRui Paulo 	len = os_strlen(settings->ssid_hex);
2165f05cddf9SRui Paulo 	if ((len & 1) || len > 2 * sizeof(cred.ssid) ||
2166f05cddf9SRui Paulo 	    hexstr2bin(settings->ssid_hex, cred.ssid, len / 2))
2167f05cddf9SRui Paulo 		return -1;
2168f05cddf9SRui Paulo 	cred.ssid_len = len / 2;
2169f05cddf9SRui Paulo 
2170f05cddf9SRui Paulo 	len = os_strlen(settings->key_hex);
2171f05cddf9SRui Paulo 	if ((len & 1) || len > 2 * sizeof(cred.key) ||
2172f05cddf9SRui Paulo 	    hexstr2bin(settings->key_hex, cred.key, len / 2))
2173f05cddf9SRui Paulo 		return -1;
2174f05cddf9SRui Paulo 	cred.key_len = len / 2;
2175f05cddf9SRui Paulo 
2176f05cddf9SRui Paulo 	if (os_strcmp(settings->auth, "OPEN") == 0)
2177f05cddf9SRui Paulo 		cred.auth_type = WPS_AUTH_OPEN;
2178f05cddf9SRui Paulo 	else if (os_strcmp(settings->auth, "WPAPSK") == 0)
2179f05cddf9SRui Paulo 		cred.auth_type = WPS_AUTH_WPAPSK;
2180f05cddf9SRui Paulo 	else if (os_strcmp(settings->auth, "WPA2PSK") == 0)
2181f05cddf9SRui Paulo 		cred.auth_type = WPS_AUTH_WPA2PSK;
2182f05cddf9SRui Paulo 	else
2183f05cddf9SRui Paulo 		return -1;
2184f05cddf9SRui Paulo 
2185f05cddf9SRui Paulo 	if (os_strcmp(settings->encr, "NONE") == 0)
2186f05cddf9SRui Paulo 		cred.encr_type = WPS_ENCR_NONE;
21875b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
2188f05cddf9SRui Paulo 	else if (os_strcmp(settings->encr, "WEP") == 0)
2189f05cddf9SRui Paulo 		cred.encr_type = WPS_ENCR_WEP;
21905b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
2191f05cddf9SRui Paulo 	else if (os_strcmp(settings->encr, "TKIP") == 0)
2192f05cddf9SRui Paulo 		cred.encr_type = WPS_ENCR_TKIP;
2193f05cddf9SRui Paulo 	else if (os_strcmp(settings->encr, "CCMP") == 0)
2194f05cddf9SRui Paulo 		cred.encr_type = WPS_ENCR_AES;
2195f05cddf9SRui Paulo 	else
2196f05cddf9SRui Paulo 		return -1;
2197f05cddf9SRui Paulo 
21985b9c547cSRui Paulo 	return wps_er_config(wpa_s->wps_er, use_uuid, use_addr,
21995b9c547cSRui Paulo 			     (const u8 *) pin, os_strlen(pin), &cred);
2200f05cddf9SRui Paulo }
2201f05cddf9SRui Paulo 
2202f05cddf9SRui Paulo 
2203f05cddf9SRui Paulo #ifdef CONFIG_WPS_NFC
wpas_wps_er_nfc_config_token(struct wpa_supplicant * wpa_s,int ndef,const char * uuid)2204f05cddf9SRui Paulo struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
2205f05cddf9SRui Paulo 					     int ndef, const char *uuid)
2206f05cddf9SRui Paulo {
2207f05cddf9SRui Paulo 	struct wpabuf *ret;
22085b9c547cSRui Paulo 	u8 u[UUID_LEN], *use_uuid = NULL;
22095b9c547cSRui Paulo 	u8 addr[ETH_ALEN], *use_addr = NULL;
2210f05cddf9SRui Paulo 
2211f05cddf9SRui Paulo 	if (!wpa_s->wps_er)
2212f05cddf9SRui Paulo 		return NULL;
2213f05cddf9SRui Paulo 
22145b9c547cSRui Paulo 	if (uuid_str2bin(uuid, u) == 0)
22155b9c547cSRui Paulo 		use_uuid = u;
22165b9c547cSRui Paulo 	else if (hwaddr_aton(uuid, addr) == 0)
22175b9c547cSRui Paulo 		use_addr = addr;
22185b9c547cSRui Paulo 	else
2219f05cddf9SRui Paulo 		return NULL;
2220f05cddf9SRui Paulo 
22215b9c547cSRui Paulo 	ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr);
2222f05cddf9SRui Paulo 	if (ndef && ret) {
2223f05cddf9SRui Paulo 		struct wpabuf *tmp;
2224f05cddf9SRui Paulo 		tmp = ndef_build_wifi(ret);
2225f05cddf9SRui Paulo 		wpabuf_free(ret);
2226f05cddf9SRui Paulo 		if (tmp == NULL)
2227f05cddf9SRui Paulo 			return NULL;
2228f05cddf9SRui Paulo 		ret = tmp;
2229f05cddf9SRui Paulo 	}
2230f05cddf9SRui Paulo 
2231f05cddf9SRui Paulo 	return ret;
2232f05cddf9SRui Paulo }
2233f05cddf9SRui Paulo #endif /* CONFIG_WPS_NFC */
2234f05cddf9SRui Paulo 
2235f05cddf9SRui Paulo 
2236f05cddf9SRui Paulo static int callbacks_pending = 0;
2237f05cddf9SRui Paulo 
wpas_wps_terminate_cb(void * ctx)2238e28a4053SRui Paulo static void wpas_wps_terminate_cb(void *ctx)
2239e28a4053SRui Paulo {
2240e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "WPS ER: Terminated");
2241f05cddf9SRui Paulo 	if (--callbacks_pending <= 0)
2242e28a4053SRui Paulo 		eloop_terminate();
2243e28a4053SRui Paulo }
2244e28a4053SRui Paulo #endif /* CONFIG_WPS_ER */
2245e28a4053SRui Paulo 
2246e28a4053SRui Paulo 
wpas_wps_terminate_pending(struct wpa_supplicant * wpa_s)2247e28a4053SRui Paulo int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s)
2248e28a4053SRui Paulo {
2249e28a4053SRui Paulo #ifdef CONFIG_WPS_ER
2250e28a4053SRui Paulo 	if (wpa_s->wps_er) {
2251f05cddf9SRui Paulo 		callbacks_pending++;
2252e28a4053SRui Paulo 		wps_er_deinit(wpa_s->wps_er, wpas_wps_terminate_cb, wpa_s);
2253e28a4053SRui Paulo 		wpa_s->wps_er = NULL;
2254e28a4053SRui Paulo 		return 1;
2255e28a4053SRui Paulo 	}
2256e28a4053SRui Paulo #endif /* CONFIG_WPS_ER */
2257e28a4053SRui Paulo 	return 0;
2258e28a4053SRui Paulo }
2259f05cddf9SRui Paulo 
2260f05cddf9SRui Paulo 
wpas_wps_update_config(struct wpa_supplicant * wpa_s)2261f05cddf9SRui Paulo void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
2262f05cddf9SRui Paulo {
2263f05cddf9SRui Paulo 	struct wps_context *wps = wpa_s->wps;
2264f05cddf9SRui Paulo 
2265f05cddf9SRui Paulo 	if (wps == NULL)
2266f05cddf9SRui Paulo 		return;
2267f05cddf9SRui Paulo 
2268f05cddf9SRui Paulo 	if (wpa_s->conf->changed_parameters & CFG_CHANGED_CONFIG_METHODS) {
2269f05cddf9SRui Paulo 		wps->config_methods = wps_config_methods_str2bin(
2270f05cddf9SRui Paulo 			wpa_s->conf->config_methods);
2271f05cddf9SRui Paulo 		if ((wps->config_methods &
2272f05cddf9SRui Paulo 		     (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) ==
2273f05cddf9SRui Paulo 		    (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) {
2274f05cddf9SRui Paulo 			wpa_printf(MSG_ERROR, "WPS: Both Label and Display "
2275f05cddf9SRui Paulo 				   "config methods are not allowed at the "
2276f05cddf9SRui Paulo 				   "same time");
2277f05cddf9SRui Paulo 			wps->config_methods &= ~WPS_CONFIG_LABEL;
2278f05cddf9SRui Paulo 		}
2279f05cddf9SRui Paulo 	}
2280f05cddf9SRui Paulo 	wps->config_methods = wps_fix_config_methods(wps->config_methods);
2281f05cddf9SRui Paulo 	wps->dev.config_methods = wps->config_methods;
2282f05cddf9SRui Paulo 
2283f05cddf9SRui Paulo 	if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE)
2284f05cddf9SRui Paulo 		os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type,
2285f05cddf9SRui Paulo 			  WPS_DEV_TYPE_LEN);
2286f05cddf9SRui Paulo 
2287f05cddf9SRui Paulo 	if (wpa_s->conf->changed_parameters & CFG_CHANGED_SEC_DEVICE_TYPE) {
2288f05cddf9SRui Paulo 		wps->dev.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
2289f05cddf9SRui Paulo 		os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type,
2290f05cddf9SRui Paulo 			  wps->dev.num_sec_dev_types * WPS_DEV_TYPE_LEN);
2291f05cddf9SRui Paulo 	}
2292f05cddf9SRui Paulo 
2293f05cddf9SRui Paulo 	if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION)
2294f05cddf9SRui Paulo 		wpas_wps_set_vendor_ext_m1(wpa_s, wps);
2295f05cddf9SRui Paulo 
2296f05cddf9SRui Paulo 	if (wpa_s->conf->changed_parameters & CFG_CHANGED_OS_VERSION)
2297f05cddf9SRui Paulo 		wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
2298f05cddf9SRui Paulo 
2299f05cddf9SRui Paulo 	if (wpa_s->conf->changed_parameters & CFG_CHANGED_UUID)
2300f05cddf9SRui Paulo 		wpas_wps_set_uuid(wpa_s, wps);
2301f05cddf9SRui Paulo 
2302f05cddf9SRui Paulo 	if (wpa_s->conf->changed_parameters &
2303f05cddf9SRui Paulo 	    (CFG_CHANGED_DEVICE_NAME | CFG_CHANGED_WPS_STRING)) {
2304f05cddf9SRui Paulo 		/* Update pointers to make sure they refer current values */
2305f05cddf9SRui Paulo 		wps->dev.device_name = wpa_s->conf->device_name;
2306f05cddf9SRui Paulo 		wps->dev.manufacturer = wpa_s->conf->manufacturer;
2307f05cddf9SRui Paulo 		wps->dev.model_name = wpa_s->conf->model_name;
2308f05cddf9SRui Paulo 		wps->dev.model_number = wpa_s->conf->model_number;
2309f05cddf9SRui Paulo 		wps->dev.serial_number = wpa_s->conf->serial_number;
2310f05cddf9SRui Paulo 	}
2311f05cddf9SRui Paulo }
2312f05cddf9SRui Paulo 
2313f05cddf9SRui Paulo 
wpas_wps_update_mac_addr(struct wpa_supplicant * wpa_s)2314c1d255d3SCy Schubert void wpas_wps_update_mac_addr(struct wpa_supplicant *wpa_s)
2315c1d255d3SCy Schubert {
2316c1d255d3SCy Schubert 	struct wps_context *wps;
2317c1d255d3SCy Schubert 
2318c1d255d3SCy Schubert 	wps = wpa_s->wps;
2319c1d255d3SCy Schubert 	if (wps)
2320c1d255d3SCy Schubert 		os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
2321c1d255d3SCy Schubert }
2322c1d255d3SCy Schubert 
2323c1d255d3SCy Schubert 
2324f05cddf9SRui Paulo #ifdef CONFIG_WPS_NFC
2325f05cddf9SRui Paulo 
23265b9c547cSRui Paulo #ifdef CONFIG_WPS_ER
23275b9c547cSRui Paulo static struct wpabuf *
wpas_wps_network_config_token(struct wpa_supplicant * wpa_s,int ndef,struct wpa_ssid * ssid)23285b9c547cSRui Paulo wpas_wps_network_config_token(struct wpa_supplicant *wpa_s, int ndef,
23295b9c547cSRui Paulo 			      struct wpa_ssid *ssid)
23305b9c547cSRui Paulo {
23315b9c547cSRui Paulo 	struct wpabuf *ret;
23325b9c547cSRui Paulo 	struct wps_credential cred;
23335b9c547cSRui Paulo 
23345b9c547cSRui Paulo 	if (wpas_wps_network_to_cred(ssid, &cred) < 0)
23355b9c547cSRui Paulo 		return NULL;
23365b9c547cSRui Paulo 
23375b9c547cSRui Paulo 	ret = wps_er_config_token_from_cred(wpa_s->wps, &cred);
23385b9c547cSRui Paulo 
23395b9c547cSRui Paulo 	if (ndef && ret) {
23405b9c547cSRui Paulo 		struct wpabuf *tmp;
23415b9c547cSRui Paulo 		tmp = ndef_build_wifi(ret);
23425b9c547cSRui Paulo 		wpabuf_free(ret);
23435b9c547cSRui Paulo 		if (tmp == NULL)
23445b9c547cSRui Paulo 			return NULL;
23455b9c547cSRui Paulo 		ret = tmp;
23465b9c547cSRui Paulo 	}
23475b9c547cSRui Paulo 
23485b9c547cSRui Paulo 	return ret;
23495b9c547cSRui Paulo }
23505b9c547cSRui Paulo #endif /* CONFIG_WPS_ER */
23515b9c547cSRui Paulo 
23525b9c547cSRui Paulo 
wpas_wps_nfc_config_token(struct wpa_supplicant * wpa_s,int ndef,const char * id_str)23535b9c547cSRui Paulo struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
23545b9c547cSRui Paulo 					  int ndef, const char *id_str)
23555b9c547cSRui Paulo {
23565b9c547cSRui Paulo #ifdef CONFIG_WPS_ER
23575b9c547cSRui Paulo 	if (id_str) {
23585b9c547cSRui Paulo 		int id;
23595b9c547cSRui Paulo 		char *end = NULL;
23605b9c547cSRui Paulo 		struct wpa_ssid *ssid;
23615b9c547cSRui Paulo 
23625b9c547cSRui Paulo 		id = strtol(id_str, &end, 10);
23635b9c547cSRui Paulo 		if (end && *end)
23645b9c547cSRui Paulo 			return NULL;
23655b9c547cSRui Paulo 
23665b9c547cSRui Paulo 		ssid = wpa_config_get_network(wpa_s->conf, id);
23675b9c547cSRui Paulo 		if (ssid == NULL)
23685b9c547cSRui Paulo 			return NULL;
23695b9c547cSRui Paulo 		return wpas_wps_network_config_token(wpa_s, ndef, ssid);
23705b9c547cSRui Paulo 	}
23715b9c547cSRui Paulo #endif /* CONFIG_WPS_ER */
23725b9c547cSRui Paulo #ifdef CONFIG_AP
23735b9c547cSRui Paulo 	if (wpa_s->ap_iface)
23745b9c547cSRui Paulo 		return wpas_ap_wps_nfc_config_token(wpa_s, ndef);
23755b9c547cSRui Paulo #endif /* CONFIG_AP */
23765b9c547cSRui Paulo 	return NULL;
23775b9c547cSRui Paulo }
23785b9c547cSRui Paulo 
23795b9c547cSRui Paulo 
wpas_wps_nfc_token(struct wpa_supplicant * wpa_s,int ndef)2380f05cddf9SRui Paulo struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef)
2381f05cddf9SRui Paulo {
23825b9c547cSRui Paulo 	if (wpa_s->conf->wps_nfc_pw_from_config) {
23835b9c547cSRui Paulo 		return wps_nfc_token_build(ndef,
23845b9c547cSRui Paulo 					   wpa_s->conf->wps_nfc_dev_pw_id,
23855b9c547cSRui Paulo 					   wpa_s->conf->wps_nfc_dh_pubkey,
23865b9c547cSRui Paulo 					   wpa_s->conf->wps_nfc_dev_pw);
23875b9c547cSRui Paulo 	}
23885b9c547cSRui Paulo 
2389f05cddf9SRui Paulo 	return wps_nfc_token_gen(ndef, &wpa_s->conf->wps_nfc_dev_pw_id,
2390f05cddf9SRui Paulo 				 &wpa_s->conf->wps_nfc_dh_pubkey,
2391f05cddf9SRui Paulo 				 &wpa_s->conf->wps_nfc_dh_privkey,
2392f05cddf9SRui Paulo 				 &wpa_s->conf->wps_nfc_dev_pw);
2393f05cddf9SRui Paulo }
2394f05cddf9SRui Paulo 
2395f05cddf9SRui Paulo 
wpas_wps_start_nfc(struct wpa_supplicant * wpa_s,const u8 * go_dev_addr,const u8 * bssid,const struct wpabuf * dev_pw,u16 dev_pw_id,int p2p_group,const u8 * peer_pubkey_hash,const u8 * ssid,size_t ssid_len,int freq)23965b9c547cSRui Paulo int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *go_dev_addr,
23975b9c547cSRui Paulo 		       const u8 *bssid,
23985b9c547cSRui Paulo 		       const struct wpabuf *dev_pw, u16 dev_pw_id,
23995b9c547cSRui Paulo 		       int p2p_group, const u8 *peer_pubkey_hash,
24005b9c547cSRui Paulo 		       const u8 *ssid, size_t ssid_len, int freq)
2401f05cddf9SRui Paulo {
2402f05cddf9SRui Paulo 	struct wps_context *wps = wpa_s->wps;
2403f05cddf9SRui Paulo 	char pw[32 * 2 + 1];
2404f05cddf9SRui Paulo 
24055b9c547cSRui Paulo 	if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && dev_pw == NULL) {
24065b9c547cSRui Paulo 		dev_pw = wpa_s->conf->wps_nfc_dev_pw;
24075b9c547cSRui Paulo 		dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id;
24085b9c547cSRui Paulo 	}
24095b9c547cSRui Paulo 
2410f05cddf9SRui Paulo 	if (wpa_s->conf->wps_nfc_dh_pubkey == NULL ||
24115b9c547cSRui Paulo 	    wpa_s->conf->wps_nfc_dh_privkey == NULL) {
24125b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Missing DH params - "
24135b9c547cSRui Paulo 			   "cannot start NFC-triggered connection");
2414f05cddf9SRui Paulo 		return -1;
24155b9c547cSRui Paulo 	}
24165b9c547cSRui Paulo 
24175b9c547cSRui Paulo 	if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && dev_pw == NULL) {
24185b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Missing Device Password (id=%u) - "
24195b9c547cSRui Paulo 			   "cannot start NFC-triggered connection", dev_pw_id);
24205b9c547cSRui Paulo 		return -1;
24215b9c547cSRui Paulo 	}
2422f05cddf9SRui Paulo 
2423f05cddf9SRui Paulo 	dh5_free(wps->dh_ctx);
2424f05cddf9SRui Paulo 	wpabuf_free(wps->dh_pubkey);
2425f05cddf9SRui Paulo 	wpabuf_free(wps->dh_privkey);
2426f05cddf9SRui Paulo 	wps->dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
2427f05cddf9SRui Paulo 	wps->dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
2428f05cddf9SRui Paulo 	if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
2429f05cddf9SRui Paulo 		wps->dh_ctx = NULL;
2430f05cddf9SRui Paulo 		wpabuf_free(wps->dh_pubkey);
2431f05cddf9SRui Paulo 		wps->dh_pubkey = NULL;
2432f05cddf9SRui Paulo 		wpabuf_free(wps->dh_privkey);
2433f05cddf9SRui Paulo 		wps->dh_privkey = NULL;
24345b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Failed to get DH priv/pub key");
2435f05cddf9SRui Paulo 		return -1;
2436f05cddf9SRui Paulo 	}
2437f05cddf9SRui Paulo 	wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
24385b9c547cSRui Paulo 	if (wps->dh_ctx == NULL) {
24395b9c547cSRui Paulo 		wpabuf_free(wps->dh_pubkey);
24405b9c547cSRui Paulo 		wps->dh_pubkey = NULL;
24415b9c547cSRui Paulo 		wpabuf_free(wps->dh_privkey);
24425b9c547cSRui Paulo 		wps->dh_privkey = NULL;
24435b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Failed to initialize DH context");
2444f05cddf9SRui Paulo 		return -1;
24455b9c547cSRui Paulo 	}
2446f05cddf9SRui Paulo 
24475b9c547cSRui Paulo 	if (dev_pw) {
2448f05cddf9SRui Paulo 		wpa_snprintf_hex_uppercase(pw, sizeof(pw),
24495b9c547cSRui Paulo 					   wpabuf_head(dev_pw),
24505b9c547cSRui Paulo 					   wpabuf_len(dev_pw));
24515b9c547cSRui Paulo 	}
24525b9c547cSRui Paulo 	return wpas_wps_start_dev_pw(wpa_s, go_dev_addr, bssid,
24535b9c547cSRui Paulo 				     dev_pw ? pw : NULL,
24545b9c547cSRui Paulo 				     p2p_group, dev_pw_id, peer_pubkey_hash,
24555b9c547cSRui Paulo 				     ssid, ssid_len, freq);
2456f05cddf9SRui Paulo }
2457f05cddf9SRui Paulo 
2458f05cddf9SRui Paulo 
wpas_wps_use_cred(struct wpa_supplicant * wpa_s,struct wps_parse_attr * attr)2459f05cddf9SRui Paulo static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
2460f05cddf9SRui Paulo 			     struct wps_parse_attr *attr)
2461f05cddf9SRui Paulo {
24625b9c547cSRui Paulo 	/*
24635b9c547cSRui Paulo 	 * Disable existing networks temporarily to allow the newly learned
24645b9c547cSRui Paulo 	 * credential to be preferred. Enable the temporarily disabled networks
24655b9c547cSRui Paulo 	 * after 10 seconds.
24665b9c547cSRui Paulo 	 */
24675b9c547cSRui Paulo 	wpas_wps_temp_disable(wpa_s, NULL);
24685b9c547cSRui Paulo 	eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
24695b9c547cSRui Paulo 			       NULL);
2470f05cddf9SRui Paulo 
2471f05cddf9SRui Paulo 	if (wps_oob_use_cred(wpa_s->wps, attr) < 0)
2472f05cddf9SRui Paulo 		return -1;
2473f05cddf9SRui Paulo 
2474f05cddf9SRui Paulo 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
2475f05cddf9SRui Paulo 		return 0;
2476f05cddf9SRui Paulo 
24775b9c547cSRui Paulo 	if (attr->ap_channel) {
24785b9c547cSRui Paulo 		u16 chan = WPA_GET_BE16(attr->ap_channel);
2479f05cddf9SRui Paulo 		int freq = 0;
2480f05cddf9SRui Paulo 
2481f05cddf9SRui Paulo 		if (chan >= 1 && chan <= 13)
2482f05cddf9SRui Paulo 			freq = 2407 + 5 * chan;
2483f05cddf9SRui Paulo 		else if (chan == 14)
2484f05cddf9SRui Paulo 			freq = 2484;
2485f05cddf9SRui Paulo 		else if (chan >= 30)
2486f05cddf9SRui Paulo 			freq = 5000 + 5 * chan;
2487f05cddf9SRui Paulo 
2488f05cddf9SRui Paulo 		if (freq) {
24895b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "WPS: Credential container indicated AP channel %u -> %u MHz",
24905b9c547cSRui Paulo 				   chan, freq);
2491f05cddf9SRui Paulo 			wpa_s->after_wps = 5;
2492f05cddf9SRui Paulo 			wpa_s->wps_freq = freq;
2493f05cddf9SRui Paulo 		}
2494f05cddf9SRui Paulo 	}
24955b9c547cSRui Paulo 
24965b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "WPS: Request reconnection with new network "
24975b9c547cSRui Paulo 		   "based on the received credential added");
24985b9c547cSRui Paulo 	wpa_s->normal_scans = 0;
24995b9c547cSRui Paulo 	wpa_supplicant_reinit_autoscan(wpa_s);
2500f05cddf9SRui Paulo 	wpa_s->disconnected = 0;
2501f05cddf9SRui Paulo 	wpa_s->reassociate = 1;
25025b9c547cSRui Paulo 
25035b9c547cSRui Paulo 	wpa_supplicant_cancel_sched_scan(wpa_s);
2504f05cddf9SRui Paulo 	wpa_supplicant_req_scan(wpa_s, 0, 0);
2505f05cddf9SRui Paulo 
2506f05cddf9SRui Paulo 	return 0;
2507f05cddf9SRui Paulo }
2508f05cddf9SRui Paulo 
2509f05cddf9SRui Paulo 
2510f05cddf9SRui Paulo #ifdef CONFIG_WPS_ER
wpas_wps_add_nfc_password_token(struct wpa_supplicant * wpa_s,struct wps_parse_attr * attr)2511f05cddf9SRui Paulo static int wpas_wps_add_nfc_password_token(struct wpa_supplicant *wpa_s,
2512f05cddf9SRui Paulo 					   struct wps_parse_attr *attr)
2513f05cddf9SRui Paulo {
2514f05cddf9SRui Paulo 	return wps_registrar_add_nfc_password_token(
2515f05cddf9SRui Paulo 		wpa_s->wps->registrar, attr->oob_dev_password,
2516f05cddf9SRui Paulo 		attr->oob_dev_password_len);
2517f05cddf9SRui Paulo }
2518f05cddf9SRui Paulo #endif /* CONFIG_WPS_ER */
2519f05cddf9SRui Paulo 
2520f05cddf9SRui Paulo 
wpas_wps_nfc_tag_process(struct wpa_supplicant * wpa_s,const struct wpabuf * wps)2521f05cddf9SRui Paulo static int wpas_wps_nfc_tag_process(struct wpa_supplicant *wpa_s,
2522f05cddf9SRui Paulo 				    const struct wpabuf *wps)
2523f05cddf9SRui Paulo {
2524f05cddf9SRui Paulo 	struct wps_parse_attr attr;
2525f05cddf9SRui Paulo 
2526f05cddf9SRui Paulo 	wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
2527f05cddf9SRui Paulo 
2528f05cddf9SRui Paulo 	if (wps_parse_msg(wps, &attr)) {
2529f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
2530f05cddf9SRui Paulo 		return -1;
2531f05cddf9SRui Paulo 	}
2532f05cddf9SRui Paulo 
2533f05cddf9SRui Paulo 	if (attr.num_cred)
2534f05cddf9SRui Paulo 		return wpas_wps_use_cred(wpa_s, &attr);
2535f05cddf9SRui Paulo 
2536f05cddf9SRui Paulo #ifdef CONFIG_WPS_ER
2537f05cddf9SRui Paulo 	if (attr.oob_dev_password)
2538f05cddf9SRui Paulo 		return wpas_wps_add_nfc_password_token(wpa_s, &attr);
2539f05cddf9SRui Paulo #endif /* CONFIG_WPS_ER */
2540f05cddf9SRui Paulo 
2541f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
2542f05cddf9SRui Paulo 	return -1;
2543f05cddf9SRui Paulo }
2544f05cddf9SRui Paulo 
2545f05cddf9SRui Paulo 
wpas_wps_nfc_tag_read(struct wpa_supplicant * wpa_s,const struct wpabuf * data,int forced_freq)2546f05cddf9SRui Paulo int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
25475b9c547cSRui Paulo 			  const struct wpabuf *data, int forced_freq)
2548f05cddf9SRui Paulo {
2549f05cddf9SRui Paulo 	const struct wpabuf *wps = data;
2550f05cddf9SRui Paulo 	struct wpabuf *tmp = NULL;
2551f05cddf9SRui Paulo 	int ret;
2552f05cddf9SRui Paulo 
2553f05cddf9SRui Paulo 	if (wpabuf_len(data) < 4)
2554f05cddf9SRui Paulo 		return -1;
2555f05cddf9SRui Paulo 
2556f05cddf9SRui Paulo 	if (*wpabuf_head_u8(data) != 0x10) {
2557f05cddf9SRui Paulo 		/* Assume this contains full NDEF record */
2558f05cddf9SRui Paulo 		tmp = ndef_parse_wifi(data);
2559f05cddf9SRui Paulo 		if (tmp == NULL) {
25605b9c547cSRui Paulo #ifdef CONFIG_P2P
25615b9c547cSRui Paulo 			tmp = ndef_parse_p2p(data);
25625b9c547cSRui Paulo 			if (tmp) {
25635b9c547cSRui Paulo 				ret = wpas_p2p_nfc_tag_process(wpa_s, tmp,
25645b9c547cSRui Paulo 							       forced_freq);
25655b9c547cSRui Paulo 				wpabuf_free(tmp);
25665b9c547cSRui Paulo 				return ret;
25675b9c547cSRui Paulo 			}
25685b9c547cSRui Paulo #endif /* CONFIG_P2P */
2569f05cddf9SRui Paulo 			wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
2570f05cddf9SRui Paulo 			return -1;
2571f05cddf9SRui Paulo 		}
2572f05cddf9SRui Paulo 		wps = tmp;
2573f05cddf9SRui Paulo 	}
2574f05cddf9SRui Paulo 
2575f05cddf9SRui Paulo 	ret = wpas_wps_nfc_tag_process(wpa_s, wps);
2576f05cddf9SRui Paulo 	wpabuf_free(tmp);
2577f05cddf9SRui Paulo 	return ret;
2578f05cddf9SRui Paulo }
2579f05cddf9SRui Paulo 
2580f05cddf9SRui Paulo 
wpas_wps_nfc_handover_req(struct wpa_supplicant * wpa_s,int ndef)25815b9c547cSRui Paulo struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s,
25825b9c547cSRui Paulo 					  int ndef)
2583f05cddf9SRui Paulo {
25845b9c547cSRui Paulo 	struct wpabuf *ret;
25855b9c547cSRui Paulo 
25865b9c547cSRui Paulo 	if (wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
25875b9c547cSRui Paulo 	    wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
25885b9c547cSRui Paulo 			   &wpa_s->conf->wps_nfc_dh_privkey) < 0)
25895b9c547cSRui Paulo 		return NULL;
25905b9c547cSRui Paulo 
25915b9c547cSRui Paulo 	ret = wps_build_nfc_handover_req(wpa_s->wps,
25925b9c547cSRui Paulo 					 wpa_s->conf->wps_nfc_dh_pubkey);
25935b9c547cSRui Paulo 
25945b9c547cSRui Paulo 	if (ndef && ret) {
25955b9c547cSRui Paulo 		struct wpabuf *tmp;
25965b9c547cSRui Paulo 		tmp = ndef_build_wifi(ret);
25975b9c547cSRui Paulo 		wpabuf_free(ret);
25985b9c547cSRui Paulo 		if (tmp == NULL)
25995b9c547cSRui Paulo 			return NULL;
26005b9c547cSRui Paulo 		ret = tmp;
26015b9c547cSRui Paulo 	}
26025b9c547cSRui Paulo 
26035b9c547cSRui Paulo 	return ret;
2604f05cddf9SRui Paulo }
2605f05cddf9SRui Paulo 
2606f05cddf9SRui Paulo 
26075b9c547cSRui Paulo #ifdef CONFIG_WPS_NFC
26085b9c547cSRui Paulo 
26095b9c547cSRui Paulo static struct wpabuf *
wpas_wps_er_nfc_handover_sel(struct wpa_supplicant * wpa_s,int ndef,const char * uuid)26105b9c547cSRui Paulo wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef,
26115b9c547cSRui Paulo 			     const char *uuid)
2612f05cddf9SRui Paulo {
26135b9c547cSRui Paulo #ifdef CONFIG_WPS_ER
26145b9c547cSRui Paulo 	struct wpabuf *ret;
26155b9c547cSRui Paulo 	u8 u[UUID_LEN], *use_uuid = NULL;
26165b9c547cSRui Paulo 	u8 addr[ETH_ALEN], *use_addr = NULL;
26175b9c547cSRui Paulo 	struct wps_context *wps = wpa_s->wps;
26185b9c547cSRui Paulo 
26195b9c547cSRui Paulo 	if (wps == NULL)
26205b9c547cSRui Paulo 		return NULL;
26215b9c547cSRui Paulo 
26225b9c547cSRui Paulo 	if (uuid == NULL)
26235b9c547cSRui Paulo 		return NULL;
26245b9c547cSRui Paulo 	if (uuid_str2bin(uuid, u) == 0)
26255b9c547cSRui Paulo 		use_uuid = u;
26265b9c547cSRui Paulo 	else if (hwaddr_aton(uuid, addr) == 0)
26275b9c547cSRui Paulo 		use_addr = addr;
26285b9c547cSRui Paulo 	else
26295b9c547cSRui Paulo 		return NULL;
26305b9c547cSRui Paulo 
26315b9c547cSRui Paulo 	if (wpa_s->conf->wps_nfc_dh_pubkey == NULL) {
26325b9c547cSRui Paulo 		if (wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
26335b9c547cSRui Paulo 				   &wpa_s->conf->wps_nfc_dh_privkey) < 0)
2634f05cddf9SRui Paulo 			return NULL;
2635f05cddf9SRui Paulo 	}
2636f05cddf9SRui Paulo 
26375b9c547cSRui Paulo 	wpas_wps_nfc_clear(wps);
26385b9c547cSRui Paulo 	wps->ap_nfc_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
26395b9c547cSRui Paulo 	wps->ap_nfc_dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
26405b9c547cSRui Paulo 	wps->ap_nfc_dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
26415b9c547cSRui Paulo 	if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey) {
26425b9c547cSRui Paulo 		wpas_wps_nfc_clear(wps);
26435b9c547cSRui Paulo 		return NULL;
26445b9c547cSRui Paulo 	}
2645f05cddf9SRui Paulo 
26465b9c547cSRui Paulo 	ret = wps_er_nfc_handover_sel(wpa_s->wps_er, wpa_s->wps, use_uuid,
26475b9c547cSRui Paulo 				      use_addr, wpa_s->conf->wps_nfc_dh_pubkey);
26485b9c547cSRui Paulo 	if (ndef && ret) {
26495b9c547cSRui Paulo 		struct wpabuf *tmp;
26505b9c547cSRui Paulo 		tmp = ndef_build_wifi(ret);
26515b9c547cSRui Paulo 		wpabuf_free(ret);
26525b9c547cSRui Paulo 		if (tmp == NULL)
26535b9c547cSRui Paulo 			return NULL;
26545b9c547cSRui Paulo 		ret = tmp;
26555b9c547cSRui Paulo 	}
26565b9c547cSRui Paulo 
26575b9c547cSRui Paulo 	return ret;
26585b9c547cSRui Paulo #else /* CONFIG_WPS_ER */
26595b9c547cSRui Paulo 	return NULL;
26605b9c547cSRui Paulo #endif /* CONFIG_WPS_ER */
26615b9c547cSRui Paulo }
26625b9c547cSRui Paulo #endif /* CONFIG_WPS_NFC */
26635b9c547cSRui Paulo 
26645b9c547cSRui Paulo 
wpas_wps_nfc_handover_sel(struct wpa_supplicant * wpa_s,int ndef,int cr,const char * uuid)26655b9c547cSRui Paulo struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
26665b9c547cSRui Paulo 					  int ndef, int cr, const char *uuid)
2667f05cddf9SRui Paulo {
26685b9c547cSRui Paulo 	struct wpabuf *ret;
26695b9c547cSRui Paulo 	if (!cr)
26705b9c547cSRui Paulo 		return NULL;
26715b9c547cSRui Paulo 	ret = wpas_ap_wps_nfc_handover_sel(wpa_s, ndef);
26725b9c547cSRui Paulo 	if (ret)
26735b9c547cSRui Paulo 		return ret;
26745b9c547cSRui Paulo 	return wpas_wps_er_nfc_handover_sel(wpa_s, ndef, uuid);
2675f05cddf9SRui Paulo }
2676f05cddf9SRui Paulo 
2677f05cddf9SRui Paulo 
wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant * wpa_s,const struct wpabuf * data)26785b9c547cSRui Paulo static int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
2679f05cddf9SRui Paulo 					const struct wpabuf *data)
2680f05cddf9SRui Paulo {
2681f05cddf9SRui Paulo 	struct wpabuf *wps;
26825b9c547cSRui Paulo 	int ret = -1;
26835b9c547cSRui Paulo 	u16 wsc_len;
26845b9c547cSRui Paulo 	const u8 *pos;
26855b9c547cSRui Paulo 	struct wpabuf msg;
26865b9c547cSRui Paulo 	struct wps_parse_attr attr;
26875b9c547cSRui Paulo 	u16 dev_pw_id;
26885b9c547cSRui Paulo 	const u8 *bssid = NULL;
26895b9c547cSRui Paulo 	int freq = 0;
2690f05cddf9SRui Paulo 
2691f05cddf9SRui Paulo 	wps = ndef_parse_wifi(data);
2692f05cddf9SRui Paulo 	if (wps == NULL)
2693f05cddf9SRui Paulo 		return -1;
2694f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
2695f05cddf9SRui Paulo 		   "payload from NFC connection handover");
26965b9c547cSRui Paulo 	wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
26975b9c547cSRui Paulo 	if (wpabuf_len(wps) < 2) {
26985b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Select "
26995b9c547cSRui Paulo 			   "Message");
27005b9c547cSRui Paulo 		goto out;
27015b9c547cSRui Paulo 	}
27025b9c547cSRui Paulo 	pos = wpabuf_head(wps);
27035b9c547cSRui Paulo 	wsc_len = WPA_GET_BE16(pos);
27045b9c547cSRui Paulo 	if (wsc_len > wpabuf_len(wps) - 2) {
27055b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
27065b9c547cSRui Paulo 			   "in Wi-Fi Handover Select Message", wsc_len);
27075b9c547cSRui Paulo 		goto out;
27085b9c547cSRui Paulo 	}
27095b9c547cSRui Paulo 	pos += 2;
2710f05cddf9SRui Paulo 
27115b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG,
27125b9c547cSRui Paulo 		    "WPS: WSC attributes in Wi-Fi Handover Select Message",
27135b9c547cSRui Paulo 		    pos, wsc_len);
27145b9c547cSRui Paulo 	if (wsc_len < wpabuf_len(wps) - 2) {
27155b9c547cSRui Paulo 		wpa_hexdump(MSG_DEBUG,
27165b9c547cSRui Paulo 			    "WPS: Ignore extra data after WSC attributes",
27175b9c547cSRui Paulo 			    pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
27185b9c547cSRui Paulo 	}
27195b9c547cSRui Paulo 
27205b9c547cSRui Paulo 	wpabuf_set(&msg, pos, wsc_len);
27215b9c547cSRui Paulo 	ret = wps_parse_msg(&msg, &attr);
27225b9c547cSRui Paulo 	if (ret < 0) {
27235b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
27245b9c547cSRui Paulo 			   "Wi-Fi Handover Select Message");
27255b9c547cSRui Paulo 		goto out;
27265b9c547cSRui Paulo 	}
27275b9c547cSRui Paulo 
27285b9c547cSRui Paulo 	if (attr.oob_dev_password == NULL ||
27295b9c547cSRui Paulo 	    attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
27305b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
27315b9c547cSRui Paulo 			   "included in Wi-Fi Handover Select Message");
27325b9c547cSRui Paulo 		ret = -1;
27335b9c547cSRui Paulo 		goto out;
27345b9c547cSRui Paulo 	}
27355b9c547cSRui Paulo 
27365b9c547cSRui Paulo 	if (attr.ssid == NULL) {
27375b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: No SSID included in Wi-Fi Handover "
27385b9c547cSRui Paulo 			   "Select Message");
27395b9c547cSRui Paulo 		ret = -1;
27405b9c547cSRui Paulo 		goto out;
27415b9c547cSRui Paulo 	}
27425b9c547cSRui Paulo 
27435b9c547cSRui Paulo 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", attr.ssid, attr.ssid_len);
27445b9c547cSRui Paulo 
27455b9c547cSRui Paulo 	if (attr.mac_addr) {
27465b9c547cSRui Paulo 		bssid = attr.mac_addr;
27475b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: MAC Address (BSSID): " MACSTR,
27485b9c547cSRui Paulo 			   MAC2STR(bssid));
27495b9c547cSRui Paulo 	}
27505b9c547cSRui Paulo 
27515b9c547cSRui Paulo 	if (attr.rf_bands)
27525b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: RF Bands: %d", *attr.rf_bands);
27535b9c547cSRui Paulo 
27545b9c547cSRui Paulo 	if (attr.ap_channel) {
27555b9c547cSRui Paulo 		u16 chan = WPA_GET_BE16(attr.ap_channel);
27565b9c547cSRui Paulo 
27575b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: AP Channel: %d", chan);
27585b9c547cSRui Paulo 
27595b9c547cSRui Paulo 		if (chan >= 1 && chan <= 13 &&
27605b9c547cSRui Paulo 		    (attr.rf_bands == NULL || *attr.rf_bands & WPS_RF_24GHZ))
27615b9c547cSRui Paulo 			freq = 2407 + 5 * chan;
27625b9c547cSRui Paulo 		else if (chan == 14 &&
27635b9c547cSRui Paulo 			 (attr.rf_bands == NULL ||
27645b9c547cSRui Paulo 			  *attr.rf_bands & WPS_RF_24GHZ))
27655b9c547cSRui Paulo 			freq = 2484;
27665b9c547cSRui Paulo 		else if (chan >= 30 &&
27675b9c547cSRui Paulo 			 (attr.rf_bands == NULL ||
27685b9c547cSRui Paulo 			  *attr.rf_bands & WPS_RF_50GHZ))
27695b9c547cSRui Paulo 			freq = 5000 + 5 * chan;
2770c1d255d3SCy Schubert 		else if (chan >= 1 && chan <= 6 &&
2771325151a3SRui Paulo 			 (attr.rf_bands == NULL ||
2772325151a3SRui Paulo 			  *attr.rf_bands & WPS_RF_60GHZ))
2773325151a3SRui Paulo 			freq = 56160 + 2160 * chan;
27745b9c547cSRui Paulo 
27755b9c547cSRui Paulo 		if (freq) {
27765b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG,
27775b9c547cSRui Paulo 				   "WPS: AP indicated channel %u -> %u MHz",
27785b9c547cSRui Paulo 				   chan, freq);
27795b9c547cSRui Paulo 		}
27805b9c547cSRui Paulo 	}
27815b9c547cSRui Paulo 
27825b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
27835b9c547cSRui Paulo 		    attr.oob_dev_password, attr.oob_dev_password_len);
27845b9c547cSRui Paulo 	dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
27855b9c547cSRui Paulo 				 WPS_OOB_PUBKEY_HASH_LEN);
27865b9c547cSRui Paulo 	if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
27875b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
27885b9c547cSRui Paulo 			   "%u in Wi-Fi Handover Select Message", dev_pw_id);
27895b9c547cSRui Paulo 		ret = -1;
27905b9c547cSRui Paulo 		goto out;
27915b9c547cSRui Paulo 	}
27925b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "WPS: AP Public Key hash",
27935b9c547cSRui Paulo 		    attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
27945b9c547cSRui Paulo 
27955b9c547cSRui Paulo 	ret = wpas_wps_start_nfc(wpa_s, NULL, bssid, NULL, dev_pw_id, 0,
27965b9c547cSRui Paulo 				 attr.oob_dev_password,
27975b9c547cSRui Paulo 				 attr.ssid, attr.ssid_len, freq);
27985b9c547cSRui Paulo 
27995b9c547cSRui Paulo out:
28005b9c547cSRui Paulo 	wpabuf_free(wps);
28015b9c547cSRui Paulo 	return ret;
28025b9c547cSRui Paulo }
28035b9c547cSRui Paulo 
28045b9c547cSRui Paulo 
wpas_wps_nfc_report_handover(struct wpa_supplicant * wpa_s,const struct wpabuf * req,const struct wpabuf * sel)28055b9c547cSRui Paulo int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
28065b9c547cSRui Paulo 				 const struct wpabuf *req,
28075b9c547cSRui Paulo 				 const struct wpabuf *sel)
28085b9c547cSRui Paulo {
28095b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "NFC: WPS connection handover reported");
28105b9c547cSRui Paulo 	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in request", req);
28115b9c547cSRui Paulo 	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in select", sel);
28125b9c547cSRui Paulo 	return wpas_wps_nfc_rx_handover_sel(wpa_s, sel);
28135b9c547cSRui Paulo }
28145b9c547cSRui Paulo 
28155b9c547cSRui Paulo 
wpas_er_wps_nfc_report_handover(struct wpa_supplicant * wpa_s,const struct wpabuf * req,const struct wpabuf * sel)28165b9c547cSRui Paulo int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
28175b9c547cSRui Paulo 				    const struct wpabuf *req,
28185b9c547cSRui Paulo 				    const struct wpabuf *sel)
28195b9c547cSRui Paulo {
28205b9c547cSRui Paulo 	struct wpabuf *wps;
28215b9c547cSRui Paulo 	int ret = -1;
28225b9c547cSRui Paulo 	u16 wsc_len;
28235b9c547cSRui Paulo 	const u8 *pos;
28245b9c547cSRui Paulo 	struct wpabuf msg;
28255b9c547cSRui Paulo 	struct wps_parse_attr attr;
28265b9c547cSRui Paulo 	u16 dev_pw_id;
28275b9c547cSRui Paulo 
28285b9c547cSRui Paulo 	/*
28295b9c547cSRui Paulo 	 * Enrollee/station is always initiator of the NFC connection handover,
28305b9c547cSRui Paulo 	 * so use the request message here to find Enrollee public key hash.
28315b9c547cSRui Paulo 	 */
28325b9c547cSRui Paulo 	wps = ndef_parse_wifi(req);
28335b9c547cSRui Paulo 	if (wps == NULL)
28345b9c547cSRui Paulo 		return -1;
28355b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
28365b9c547cSRui Paulo 		   "payload from NFC connection handover");
28375b9c547cSRui Paulo 	wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
28385b9c547cSRui Paulo 	if (wpabuf_len(wps) < 2) {
28395b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Request "
28405b9c547cSRui Paulo 			   "Message");
28415b9c547cSRui Paulo 		goto out;
28425b9c547cSRui Paulo 	}
28435b9c547cSRui Paulo 	pos = wpabuf_head(wps);
28445b9c547cSRui Paulo 	wsc_len = WPA_GET_BE16(pos);
28455b9c547cSRui Paulo 	if (wsc_len > wpabuf_len(wps) - 2) {
28465b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
28475b9c547cSRui Paulo 			   "in rt Wi-Fi Handover Request Message", wsc_len);
28485b9c547cSRui Paulo 		goto out;
28495b9c547cSRui Paulo 	}
28505b9c547cSRui Paulo 	pos += 2;
28515b9c547cSRui Paulo 
28525b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG,
28535b9c547cSRui Paulo 		    "WPS: WSC attributes in Wi-Fi Handover Request Message",
28545b9c547cSRui Paulo 		    pos, wsc_len);
28555b9c547cSRui Paulo 	if (wsc_len < wpabuf_len(wps) - 2) {
28565b9c547cSRui Paulo 		wpa_hexdump(MSG_DEBUG,
28575b9c547cSRui Paulo 			    "WPS: Ignore extra data after WSC attributes",
28585b9c547cSRui Paulo 			    pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
28595b9c547cSRui Paulo 	}
28605b9c547cSRui Paulo 
28615b9c547cSRui Paulo 	wpabuf_set(&msg, pos, wsc_len);
28625b9c547cSRui Paulo 	ret = wps_parse_msg(&msg, &attr);
28635b9c547cSRui Paulo 	if (ret < 0) {
28645b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
28655b9c547cSRui Paulo 			   "Wi-Fi Handover Request Message");
28665b9c547cSRui Paulo 		goto out;
28675b9c547cSRui Paulo 	}
28685b9c547cSRui Paulo 
28695b9c547cSRui Paulo 	if (attr.oob_dev_password == NULL ||
28705b9c547cSRui Paulo 	    attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
28715b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
28725b9c547cSRui Paulo 			   "included in Wi-Fi Handover Request Message");
28735b9c547cSRui Paulo 		ret = -1;
28745b9c547cSRui Paulo 		goto out;
28755b9c547cSRui Paulo 	}
28765b9c547cSRui Paulo 
28775b9c547cSRui Paulo 	if (attr.uuid_e == NULL) {
28785b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: No UUID-E included in Wi-Fi "
28795b9c547cSRui Paulo 			   "Handover Request Message");
28805b9c547cSRui Paulo 		ret = -1;
28815b9c547cSRui Paulo 		goto out;
28825b9c547cSRui Paulo 	}
28835b9c547cSRui Paulo 
28845b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", attr.uuid_e, WPS_UUID_LEN);
28855b9c547cSRui Paulo 
28865b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
28875b9c547cSRui Paulo 		    attr.oob_dev_password, attr.oob_dev_password_len);
28885b9c547cSRui Paulo 	dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
28895b9c547cSRui Paulo 				 WPS_OOB_PUBKEY_HASH_LEN);
28905b9c547cSRui Paulo 	if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
28915b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
28925b9c547cSRui Paulo 			   "%u in Wi-Fi Handover Request Message", dev_pw_id);
28935b9c547cSRui Paulo 		ret = -1;
28945b9c547cSRui Paulo 		goto out;
28955b9c547cSRui Paulo 	}
28965b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Public Key hash",
28975b9c547cSRui Paulo 		    attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
28985b9c547cSRui Paulo 
28995b9c547cSRui Paulo 	ret = wps_registrar_add_nfc_pw_token(wpa_s->wps->registrar,
29005b9c547cSRui Paulo 					     attr.oob_dev_password,
29015b9c547cSRui Paulo 					     DEV_PW_NFC_CONNECTION_HANDOVER,
29025b9c547cSRui Paulo 					     NULL, 0, 1);
29035b9c547cSRui Paulo 
29045b9c547cSRui Paulo out:
29055b9c547cSRui Paulo 	wpabuf_free(wps);
2906f05cddf9SRui Paulo 	return ret;
2907f05cddf9SRui Paulo }
2908f05cddf9SRui Paulo 
2909f05cddf9SRui Paulo #endif /* CONFIG_WPS_NFC */
2910f05cddf9SRui Paulo 
2911f05cddf9SRui Paulo 
wpas_wps_dump_ap_info(struct wpa_supplicant * wpa_s)2912f05cddf9SRui Paulo static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s)
2913f05cddf9SRui Paulo {
2914f05cddf9SRui Paulo 	size_t i;
29155b9c547cSRui Paulo 	struct os_reltime now;
2916f05cddf9SRui Paulo 
2917f05cddf9SRui Paulo 	if (wpa_debug_level > MSG_DEBUG)
2918f05cddf9SRui Paulo 		return;
2919f05cddf9SRui Paulo 
2920f05cddf9SRui Paulo 	if (wpa_s->wps_ap == NULL)
2921f05cddf9SRui Paulo 		return;
2922f05cddf9SRui Paulo 
29235b9c547cSRui Paulo 	os_get_reltime(&now);
2924f05cddf9SRui Paulo 
2925f05cddf9SRui Paulo 	for (i = 0; i < wpa_s->num_wps_ap; i++) {
2926f05cddf9SRui Paulo 		struct wps_ap_info *ap = &wpa_s->wps_ap[i];
2927c1d255d3SCy Schubert 		struct wpa_bssid_ignore *e = wpa_bssid_ignore_get(wpa_s,
2928c1d255d3SCy Schubert 								  ap->bssid);
2929f05cddf9SRui Paulo 
2930f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: AP[%d] " MACSTR " type=%d "
2931c1d255d3SCy Schubert 			   "tries=%d last_attempt=%d sec ago bssid_ignore=%d",
2932f05cddf9SRui Paulo 			   (int) i, MAC2STR(ap->bssid), ap->type, ap->tries,
2933f05cddf9SRui Paulo 			   ap->last_attempt.sec > 0 ?
2934f05cddf9SRui Paulo 			   (int) now.sec - (int) ap->last_attempt.sec : -1,
2935f05cddf9SRui Paulo 			   e ? e->count : 0);
2936f05cddf9SRui Paulo 	}
2937f05cddf9SRui Paulo }
2938f05cddf9SRui Paulo 
2939f05cddf9SRui Paulo 
wpas_wps_get_ap_info(struct wpa_supplicant * wpa_s,const u8 * bssid)2940f05cddf9SRui Paulo static struct wps_ap_info * wpas_wps_get_ap_info(struct wpa_supplicant *wpa_s,
2941f05cddf9SRui Paulo 						 const u8 *bssid)
2942f05cddf9SRui Paulo {
2943f05cddf9SRui Paulo 	size_t i;
2944f05cddf9SRui Paulo 
2945f05cddf9SRui Paulo 	if (wpa_s->wps_ap == NULL)
2946f05cddf9SRui Paulo 		return NULL;
2947f05cddf9SRui Paulo 
2948f05cddf9SRui Paulo 	for (i = 0; i < wpa_s->num_wps_ap; i++) {
2949f05cddf9SRui Paulo 		struct wps_ap_info *ap = &wpa_s->wps_ap[i];
2950*a90b9d01SCy Schubert 		if (ether_addr_equal(ap->bssid, bssid))
2951f05cddf9SRui Paulo 			return ap;
2952f05cddf9SRui Paulo 	}
2953f05cddf9SRui Paulo 
2954f05cddf9SRui Paulo 	return NULL;
2955f05cddf9SRui Paulo }
2956f05cddf9SRui Paulo 
2957f05cddf9SRui Paulo 
wpas_wps_update_ap_info_bss(struct wpa_supplicant * wpa_s,struct wpa_scan_res * res)2958f05cddf9SRui Paulo static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
2959f05cddf9SRui Paulo 					struct wpa_scan_res *res)
2960f05cddf9SRui Paulo {
2961f05cddf9SRui Paulo 	struct wpabuf *wps;
2962f05cddf9SRui Paulo 	enum wps_ap_info_type type;
2963f05cddf9SRui Paulo 	struct wps_ap_info *ap;
2964325151a3SRui Paulo 	int r, pbc_active;
2965325151a3SRui Paulo 	const u8 *uuid;
2966f05cddf9SRui Paulo 
2967f05cddf9SRui Paulo 	if (wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE) == NULL)
2968f05cddf9SRui Paulo 		return;
2969f05cddf9SRui Paulo 
2970f05cddf9SRui Paulo 	wps = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
2971f05cddf9SRui Paulo 	if (wps == NULL)
2972f05cddf9SRui Paulo 		return;
2973f05cddf9SRui Paulo 
2974f05cddf9SRui Paulo 	r = wps_is_addr_authorized(wps, wpa_s->own_addr, 1);
2975f05cddf9SRui Paulo 	if (r == 2)
2976f05cddf9SRui Paulo 		type = WPS_AP_SEL_REG_OUR;
2977f05cddf9SRui Paulo 	else if (r == 1)
2978f05cddf9SRui Paulo 		type = WPS_AP_SEL_REG;
2979f05cddf9SRui Paulo 	else
2980f05cddf9SRui Paulo 		type = WPS_AP_NOT_SEL_REG;
2981f05cddf9SRui Paulo 
2982325151a3SRui Paulo 	uuid = wps_get_uuid_e(wps);
2983325151a3SRui Paulo 	pbc_active = wps_is_selected_pbc_registrar(wps);
2984f05cddf9SRui Paulo 
2985f05cddf9SRui Paulo 	ap = wpas_wps_get_ap_info(wpa_s, res->bssid);
2986f05cddf9SRui Paulo 	if (ap) {
2987f05cddf9SRui Paulo 		if (ap->type != type) {
2988f05cddf9SRui Paulo 			wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR
2989f05cddf9SRui Paulo 				   " changed type %d -> %d",
2990f05cddf9SRui Paulo 				   MAC2STR(res->bssid), ap->type, type);
2991f05cddf9SRui Paulo 			ap->type = type;
2992f05cddf9SRui Paulo 			if (type != WPS_AP_NOT_SEL_REG)
2993c1d255d3SCy Schubert 				wpa_bssid_ignore_del(wpa_s, ap->bssid);
2994f05cddf9SRui Paulo 		}
2995325151a3SRui Paulo 		ap->pbc_active = pbc_active;
2996325151a3SRui Paulo 		if (uuid)
2997325151a3SRui Paulo 			os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
2998325151a3SRui Paulo 		goto out;
2999f05cddf9SRui Paulo 	}
3000f05cddf9SRui Paulo 
3001f05cddf9SRui Paulo 	ap = os_realloc_array(wpa_s->wps_ap, wpa_s->num_wps_ap + 1,
3002f05cddf9SRui Paulo 			      sizeof(struct wps_ap_info));
3003f05cddf9SRui Paulo 	if (ap == NULL)
3004325151a3SRui Paulo 		goto out;
3005f05cddf9SRui Paulo 
3006f05cddf9SRui Paulo 	wpa_s->wps_ap = ap;
3007f05cddf9SRui Paulo 	ap = &wpa_s->wps_ap[wpa_s->num_wps_ap];
3008f05cddf9SRui Paulo 	wpa_s->num_wps_ap++;
3009f05cddf9SRui Paulo 
3010f05cddf9SRui Paulo 	os_memset(ap, 0, sizeof(*ap));
3011f05cddf9SRui Paulo 	os_memcpy(ap->bssid, res->bssid, ETH_ALEN);
3012f05cddf9SRui Paulo 	ap->type = type;
3013325151a3SRui Paulo 	ap->pbc_active = pbc_active;
3014325151a3SRui Paulo 	if (uuid)
3015325151a3SRui Paulo 		os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
3016f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " type %d added",
3017f05cddf9SRui Paulo 		   MAC2STR(ap->bssid), ap->type);
3018325151a3SRui Paulo 
3019325151a3SRui Paulo out:
3020325151a3SRui Paulo 	wpabuf_free(wps);
3021f05cddf9SRui Paulo }
3022f05cddf9SRui Paulo 
3023f05cddf9SRui Paulo 
wpas_wps_update_ap_info(struct wpa_supplicant * wpa_s,struct wpa_scan_results * scan_res)3024f05cddf9SRui Paulo void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
3025f05cddf9SRui Paulo 			     struct wpa_scan_results *scan_res)
3026f05cddf9SRui Paulo {
3027f05cddf9SRui Paulo 	size_t i;
3028f05cddf9SRui Paulo 
3029f05cddf9SRui Paulo 	for (i = 0; i < scan_res->num; i++)
3030f05cddf9SRui Paulo 		wpas_wps_update_ap_info_bss(wpa_s, scan_res->res[i]);
3031f05cddf9SRui Paulo 
3032f05cddf9SRui Paulo 	wpas_wps_dump_ap_info(wpa_s);
3033f05cddf9SRui Paulo }
3034f05cddf9SRui Paulo 
3035f05cddf9SRui Paulo 
wpas_wps_partner_link_scan_done(struct wpa_supplicant * wpa_s)3036*a90b9d01SCy Schubert bool wpas_wps_partner_link_scan_done(struct wpa_supplicant *wpa_s)
3037*a90b9d01SCy Schubert {
3038*a90b9d01SCy Schubert 	struct wpa_global *global = wpa_s->global;
3039*a90b9d01SCy Schubert 	struct wpa_supplicant *iface;
3040*a90b9d01SCy Schubert 
3041*a90b9d01SCy Schubert 	for (iface = global->ifaces; iface; iface = iface->next) {
3042*a90b9d01SCy Schubert 		if (iface == wpa_s)
3043*a90b9d01SCy Schubert 			continue;
3044*a90b9d01SCy Schubert 
3045*a90b9d01SCy Schubert 		if (!iface->supp_pbc_active)
3046*a90b9d01SCy Schubert 			continue;
3047*a90b9d01SCy Schubert 
3048*a90b9d01SCy Schubert 		/* Scan results are available for both links. While the current
3049*a90b9d01SCy Schubert 		 * link will proceed for network selection, ensure the partner
3050*a90b9d01SCy Schubert 		 * link also gets an attempt at network selection and connect
3051*a90b9d01SCy Schubert 		 * with the selected BSS. */
3052*a90b9d01SCy Schubert 		if (iface->wps_scan_done)
3053*a90b9d01SCy Schubert 			wpa_wps_supplicant_fast_associate(iface);
3054*a90b9d01SCy Schubert 		else
3055*a90b9d01SCy Schubert 			return false;
3056*a90b9d01SCy Schubert 	}
3057*a90b9d01SCy Schubert 
3058*a90b9d01SCy Schubert 	return true;
3059*a90b9d01SCy Schubert }
3060*a90b9d01SCy Schubert 
3061*a90b9d01SCy Schubert 
wpas_wps_partner_link_overlap_detect(struct wpa_supplicant * wpa_s)3062*a90b9d01SCy Schubert bool wpas_wps_partner_link_overlap_detect(struct wpa_supplicant *wpa_s)
3063*a90b9d01SCy Schubert {
3064*a90b9d01SCy Schubert 	struct wpa_global *global = wpa_s->global;
3065*a90b9d01SCy Schubert 	struct wpa_supplicant *iface;
3066*a90b9d01SCy Schubert 
3067*a90b9d01SCy Schubert 	for (iface = global->ifaces; iface; iface = iface->next) {
3068*a90b9d01SCy Schubert 		if (iface == wpa_s)
3069*a90b9d01SCy Schubert 			continue;
3070*a90b9d01SCy Schubert 		if (iface->wps_overlap)
3071*a90b9d01SCy Schubert 			return true;
3072*a90b9d01SCy Schubert 	}
3073*a90b9d01SCy Schubert 
3074*a90b9d01SCy Schubert 	return false;
3075*a90b9d01SCy Schubert }
3076*a90b9d01SCy Schubert 
3077*a90b9d01SCy Schubert 
wpas_wps_notify_assoc(struct wpa_supplicant * wpa_s,const u8 * bssid)3078f05cddf9SRui Paulo void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid)
3079f05cddf9SRui Paulo {
3080f05cddf9SRui Paulo 	struct wps_ap_info *ap;
30815b9c547cSRui Paulo 
30825b9c547cSRui Paulo 	wpa_s->after_wps = 0;
30835b9c547cSRui Paulo 
3084f05cddf9SRui Paulo 	if (!wpa_s->wps_ap_iter)
3085f05cddf9SRui Paulo 		return;
3086f05cddf9SRui Paulo 	ap = wpas_wps_get_ap_info(wpa_s, bssid);
3087f05cddf9SRui Paulo 	if (ap == NULL)
3088f05cddf9SRui Paulo 		return;
3089f05cddf9SRui Paulo 	ap->tries++;
30905b9c547cSRui Paulo 	os_get_reltime(&ap->last_attempt);
3091f05cddf9SRui Paulo }
3092