blob: 81e11e76c7fb0cb0e9cbf4214772e876160d584b [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * wpa_supplicant / WPS integration
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003 * Copyright (c) 2008-2014, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "eloop.h"
13#include "uuid.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070014#include "crypto/random.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070015#include "crypto/dh_group5.h"
16#include "common/ieee802_11_defs.h"
17#include "common/ieee802_11_common.h"
18#include "common/wpa_common.h"
19#include "common/wpa_ctrl.h"
20#include "eap_common/eap_wsc_common.h"
21#include "eap_peer/eap.h"
Jouni Malinen75ecf522011-06-27 15:19:46 -070022#include "eapol_supp/eapol_supp_sm.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070023#include "rsn_supp/wpa.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070024#include "wps/wps_attr_parse.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070025#include "config.h"
26#include "wpa_supplicant_i.h"
27#include "driver_i.h"
28#include "notify.h"
Hai Shalom60840252021-02-19 19:02:11 -080029#include "bssid_ignore.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070030#include "bss.h"
31#include "scan.h"
32#include "ap.h"
33#include "p2p/p2p.h"
34#include "p2p_supplicant.h"
35#include "wps_supplicant.h"
36
37
38#ifndef WPS_PIN_SCAN_IGNORE_SEL_REG
39#define WPS_PIN_SCAN_IGNORE_SEL_REG 3
40#endif /* WPS_PIN_SCAN_IGNORE_SEL_REG */
41
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070042/*
43 * The minimum time in seconds before trying to associate to a WPS PIN AP that
44 * does not have Selected Registrar TRUE.
45 */
46#ifndef WPS_PIN_TIME_IGNORE_SEL_REG
47#define WPS_PIN_TIME_IGNORE_SEL_REG 5
48#endif /* WPS_PIN_TIME_IGNORE_SEL_REG */
49
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070050static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
51static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
52
53
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070054static void wpas_wps_clear_ap_info(struct wpa_supplicant *wpa_s)
55{
56 os_free(wpa_s->wps_ap);
57 wpa_s->wps_ap = NULL;
58 wpa_s->num_wps_ap = 0;
59 wpa_s->wps_ap_iter = 0;
60}
61
62
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -070063static void wpas_wps_assoc_with_cred(void *eloop_ctx, void *timeout_ctx)
64{
65 struct wpa_supplicant *wpa_s = eloop_ctx;
66 int use_fast_assoc = timeout_ctx != NULL;
67
68 wpa_printf(MSG_DEBUG, "WPS: Continuing association after eapol_cb");
69 if (!use_fast_assoc ||
70 wpa_supplicant_fast_associate(wpa_s) != 1)
71 wpa_supplicant_req_scan(wpa_s, 0, 0);
72}
73
74
75static void wpas_wps_assoc_with_cred_cancel(struct wpa_supplicant *wpa_s)
76{
77 eloop_cancel_timeout(wpas_wps_assoc_with_cred, wpa_s, (void *) 0);
78 eloop_cancel_timeout(wpas_wps_assoc_with_cred, wpa_s, (void *) 1);
79}
80
81
Sunil Ravi38ad1ed2023-01-17 23:58:31 +000082static struct wpabuf * wpas_wps_get_wps_ie(struct wpa_bss *bss)
83{
84 /* Return the latest receive WPS IE from the AP regardless of whether
85 * it was from a Beacon frame or Probe Response frame to avoid using
86 * stale information. */
87 if (bss->beacon_newer)
88 return wpa_bss_get_vendor_ie_multi_beacon(bss,
89 WPS_IE_VENDOR_TYPE);
90 return wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
91}
92
93
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070094int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
95{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080096 if (wpas_p2p_wps_eapol_cb(wpa_s) > 0)
97 return 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080098
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070099 if (!wpa_s->wps_success &&
100 wpa_s->current_ssid &&
101 eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
102 const u8 *bssid = wpa_s->bssid;
103 if (is_zero_ether_addr(bssid))
104 bssid = wpa_s->pending_bssid;
105
106 wpa_printf(MSG_DEBUG, "WPS: PIN registration with " MACSTR
107 " did not succeed - continue trying to find "
108 "suitable AP", MAC2STR(bssid));
Hai Shalom60840252021-02-19 19:02:11 -0800109 wpa_bssid_ignore_add(wpa_s, bssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700110
111 wpa_supplicant_deauthenticate(wpa_s,
112 WLAN_REASON_DEAUTH_LEAVING);
113 wpa_s->reassociate = 1;
114 wpa_supplicant_req_scan(wpa_s,
Hai Shalom60840252021-02-19 19:02:11 -0800115 wpa_s->bssid_ignore_cleared ? 5 : 0, 0);
116 wpa_s->bssid_ignore_cleared = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700117 return 1;
118 }
119
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700120 wpas_wps_clear_ap_info(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700121 eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
122 if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && !wpa_s->wps_success)
123 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL);
124
125 if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid &&
126 !(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
127 int disabled = wpa_s->current_ssid->disabled;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800128 unsigned int freq = wpa_s->assoc_freq;
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700129 struct wpa_bss *bss;
130 struct wpa_ssid *ssid = NULL;
131 int use_fast_assoc = 0;
132
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700133 wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800134 "try to associate with the received credential "
135 "(freq=%u)", freq);
Dmitry Shmidt203eadb2015-03-05 14:16:04 -0800136 wpa_s->own_disconnect_req = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700137 wpa_supplicant_deauthenticate(wpa_s,
138 WLAN_REASON_DEAUTH_LEAVING);
139 if (disabled) {
140 wpa_printf(MSG_DEBUG, "WPS: Current network is "
141 "disabled - wait for user to enable");
142 return 1;
143 }
144 wpa_s->after_wps = 5;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800145 wpa_s->wps_freq = freq;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800146 wpa_s->normal_scans = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700147 wpa_s->reassociate = 1;
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700148
149 wpa_printf(MSG_DEBUG, "WPS: Checking whether fast association "
150 "without a new scan can be used");
151 bss = wpa_supplicant_pick_network(wpa_s, &ssid);
152 if (bss) {
153 struct wpabuf *wps;
154 struct wps_parse_attr attr;
155
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000156 wps = wpas_wps_get_wps_ie(bss);
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700157 if (wps && wps_parse_msg(wps, &attr) == 0 &&
158 attr.wps_state &&
159 *attr.wps_state == WPS_STATE_CONFIGURED)
160 use_fast_assoc = 1;
161 wpabuf_free(wps);
162 }
163
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -0700164 /*
165 * Complete the next step from an eloop timeout to allow pending
166 * driver events related to the disconnection to be processed
167 * first. This makes it less likely for disconnection event to
168 * cause problems with the following connection.
169 */
170 wpa_printf(MSG_DEBUG, "WPS: Continue association from timeout");
171 wpas_wps_assoc_with_cred_cancel(wpa_s);
172 eloop_register_timeout(0, 10000,
173 wpas_wps_assoc_with_cred, wpa_s,
174 use_fast_assoc ? (void *) 1 :
175 (void *) 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700176 return 1;
177 }
178
179 if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid) {
180 wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting "
181 "for external credential processing");
182 wpas_clear_wps(wpa_s);
Dmitry Shmidt203eadb2015-03-05 14:16:04 -0800183 wpa_s->own_disconnect_req = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700184 wpa_supplicant_deauthenticate(wpa_s,
185 WLAN_REASON_DEAUTH_LEAVING);
186 return 1;
187 }
188
189 return 0;
190}
191
192
193static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
194 struct wpa_ssid *ssid,
195 const struct wps_credential *cred)
196{
197 struct wpa_driver_capa capa;
198 struct wpa_bss *bss;
199 const u8 *ie;
200 struct wpa_ie_data adv;
201 int wpa2 = 0, ccmp = 0;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700202 enum wpa_driver_if_type iftype;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700203
204 /*
205 * Many existing WPS APs do not know how to negotiate WPA2 or CCMP in
206 * case they are configured for mixed mode operation (WPA+WPA2 and
207 * TKIP+CCMP). Try to use scan results to figure out whether the AP
208 * actually supports stronger security and select that if the client
209 * has support for it, too.
210 */
211
212 if (wpa_drv_get_capa(wpa_s, &capa))
213 return; /* Unknown what driver supports */
214
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800215 if (ssid->ssid == NULL)
216 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700217 bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700218 if (!bss)
219 bss = wpa_bss_get(wpa_s, wpa_s->bssid,
220 ssid->ssid, ssid->ssid_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700221 if (bss == NULL) {
222 wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS "
223 "table - use credential as-is");
224 return;
225 }
226
227 wpa_printf(MSG_DEBUG, "WPS: AP found from BSS table");
228
229 ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
230 if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0) {
231 wpa2 = 1;
232 if (adv.pairwise_cipher & WPA_CIPHER_CCMP)
233 ccmp = 1;
234 } else {
235 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
236 if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0 &&
237 adv.pairwise_cipher & WPA_CIPHER_CCMP)
238 ccmp = 1;
239 }
240
241 if (ie == NULL && (ssid->proto & WPA_PROTO_WPA) &&
242 (ssid->pairwise_cipher & WPA_CIPHER_TKIP)) {
243 /*
244 * TODO: This could be the initial AP configuration and the
245 * Beacon contents could change shortly. Should request a new
246 * scan and delay addition of the network until the updated
247 * scan results are available.
248 */
249 wpa_printf(MSG_DEBUG, "WPS: The AP did not yet advertise WPA "
250 "support - use credential as-is");
251 return;
252 }
253
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700254 iftype = ssid->p2p_group ? WPA_IF_P2P_CLIENT : WPA_IF_STATION;
255
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700256 if (ccmp && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
257 (ssid->pairwise_cipher & WPA_CIPHER_TKIP) &&
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700258 (capa.key_mgmt_iftype[iftype] &
259 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700260 wpa_printf(MSG_DEBUG, "WPS: Add CCMP into the credential "
261 "based on scan results");
262 if (wpa_s->conf->ap_scan == 1)
263 ssid->pairwise_cipher |= WPA_CIPHER_CCMP;
264 else
265 ssid->pairwise_cipher = WPA_CIPHER_CCMP;
266 }
267
268 if (wpa2 && !(ssid->proto & WPA_PROTO_RSN) &&
269 (ssid->proto & WPA_PROTO_WPA) &&
270 (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP)) {
271 wpa_printf(MSG_DEBUG, "WPS: Add WPA2 into the credential "
272 "based on scan results");
273 if (wpa_s->conf->ap_scan == 1)
274 ssid->proto |= WPA_PROTO_RSN;
275 else
276 ssid->proto = WPA_PROTO_RSN;
277 }
278}
279
280
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -0700281static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s,
282 struct wpa_ssid *new_ssid)
283{
284 struct wpa_ssid *ssid, *next;
285
286 for (ssid = wpa_s->conf->ssid, next = ssid ? ssid->next : NULL; ssid;
287 ssid = next, next = ssid ? ssid->next : NULL) {
288 /*
289 * new_ssid has already been added to the list in
290 * wpas_wps_add_network(), so skip it.
291 */
292 if (ssid == new_ssid)
293 continue;
294
295 if (ssid->bssid_set || new_ssid->bssid_set) {
296 if (ssid->bssid_set != new_ssid->bssid_set)
297 continue;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000298 if (!ether_addr_equal(ssid->bssid, new_ssid->bssid))
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -0700299 continue;
300 }
301
302 /* compare SSID */
303 if (ssid->ssid_len == 0 || ssid->ssid_len != new_ssid->ssid_len)
304 continue;
305
306 if (ssid->ssid && new_ssid->ssid) {
307 if (os_memcmp(ssid->ssid, new_ssid->ssid,
308 ssid->ssid_len) != 0)
309 continue;
310 } else if (ssid->ssid || new_ssid->ssid)
311 continue;
312
313 /* compare security parameters */
314 if (ssid->auth_alg != new_ssid->auth_alg ||
315 ssid->key_mgmt != new_ssid->key_mgmt ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800316 (ssid->group_cipher != new_ssid->group_cipher &&
317 !(ssid->group_cipher & new_ssid->group_cipher &
318 WPA_CIPHER_CCMP)))
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -0700319 continue;
320
Dmitry Shmidt661b4f72014-09-29 14:58:27 -0700321 /*
322 * Some existing WPS APs will send two creds in case they are
323 * configured for mixed mode operation (WPA+WPA2 and TKIP+CCMP).
324 * Try to merge these two creds if they are received in the same
325 * M8 message.
326 */
327 if (ssid->wps_run && ssid->wps_run == new_ssid->wps_run &&
328 wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
329 if (new_ssid->passphrase && ssid->passphrase &&
330 os_strcmp(new_ssid->passphrase, ssid->passphrase) !=
331 0) {
332 wpa_printf(MSG_DEBUG,
333 "WPS: M8 Creds with different passphrase - do not merge");
334 continue;
335 }
336
337 if (new_ssid->psk_set &&
338 (!ssid->psk_set ||
339 os_memcmp(new_ssid->psk, ssid->psk, 32) != 0)) {
340 wpa_printf(MSG_DEBUG,
341 "WPS: M8 Creds with different PSK - do not merge");
342 continue;
343 }
344
345 if ((new_ssid->passphrase && !ssid->passphrase) ||
346 (!new_ssid->passphrase && ssid->passphrase)) {
347 wpa_printf(MSG_DEBUG,
348 "WPS: M8 Creds with different passphrase/PSK type - do not merge");
349 continue;
350 }
351
352 wpa_printf(MSG_DEBUG,
353 "WPS: Workaround - merge likely WPA/WPA2-mixed mode creds in same M8 message");
354 new_ssid->proto |= ssid->proto;
355 new_ssid->pairwise_cipher |= ssid->pairwise_cipher;
356 } else {
357 /*
358 * proto and pairwise_cipher difference matter for
359 * non-mixed-mode creds.
360 */
361 if (ssid->proto != new_ssid->proto ||
362 ssid->pairwise_cipher != new_ssid->pairwise_cipher)
363 continue;
364 }
365
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -0700366 /* Remove the duplicated older network entry. */
367 wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id);
368 wpas_notify_network_removed(wpa_s, ssid);
369 wpa_config_remove_network(wpa_s->conf, ssid->id);
370 }
371}
372
373
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700374static int wpa_supplicant_wps_cred(void *ctx,
375 const struct wps_credential *cred)
376{
377 struct wpa_supplicant *wpa_s = ctx;
378 struct wpa_ssid *ssid = wpa_s->current_ssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700379 u16 auth_type;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800380#ifdef CONFIG_WPS_REG_DISABLE_OPEN
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700381 int registrar = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800382#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
Hai Shaloma20dcd72022-02-04 13:43:00 -0800383 bool add_sae;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700384
385 if ((wpa_s->conf->wps_cred_processing == 1 ||
386 wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) {
387 size_t blen = cred->cred_attr_len * 2 + 1;
388 char *buf = os_malloc(blen);
389 if (buf) {
390 wpa_snprintf_hex(buf, blen,
391 cred->cred_attr, cred->cred_attr_len);
392 wpa_msg(wpa_s, MSG_INFO, "%s%s",
393 WPS_EVENT_CRED_RECEIVED, buf);
394 os_free(buf);
395 }
396
397 wpas_notify_wps_credential(wpa_s, cred);
398 } else
399 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED);
400
401 wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
402 cred->cred_attr, cred->cred_attr_len);
403
404 if (wpa_s->conf->wps_cred_processing == 1)
405 return 0;
406
407 wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
408 wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
409 cred->auth_type);
410 wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
411 wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
412 wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
413 cred->key, cred->key_len);
414 wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
415 MAC2STR(cred->mac_addr));
416
417 auth_type = cred->auth_type;
418 if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
419 wpa_printf(MSG_DEBUG, "WPS: Workaround - convert mixed-mode "
420 "auth_type into WPA2PSK");
421 auth_type = WPS_AUTH_WPA2PSK;
422 }
423
424 if (auth_type != WPS_AUTH_OPEN &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700425 auth_type != WPS_AUTH_WPAPSK &&
426 auth_type != WPS_AUTH_WPA2PSK) {
427 wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
428 "unsupported authentication type 0x%x",
429 auth_type);
430 return 0;
431 }
432
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800433 if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) {
434 if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) {
435 wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with "
436 "invalid Network Key length %lu",
437 (unsigned long) cred->key_len);
438 return -1;
439 }
440 }
441
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700442 if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
443 wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
444 "on the received credential");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800445#ifdef CONFIG_WPS_REG_DISABLE_OPEN
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700446 if (ssid->eap.identity &&
447 ssid->eap.identity_len == WSC_ID_REGISTRAR_LEN &&
448 os_memcmp(ssid->eap.identity, WSC_ID_REGISTRAR,
449 WSC_ID_REGISTRAR_LEN) == 0)
450 registrar = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800451#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700452 os_free(ssid->eap.identity);
453 ssid->eap.identity = NULL;
454 ssid->eap.identity_len = 0;
455 os_free(ssid->eap.phase1);
456 ssid->eap.phase1 = NULL;
457 os_free(ssid->eap.eap_methods);
458 ssid->eap.eap_methods = NULL;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700459 if (!ssid->p2p_group) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700460 ssid->temporary = 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700461 ssid->bssid_set = 0;
462 }
463 ssid->disabled_until.sec = 0;
464 ssid->disabled_until.usec = 0;
465 ssid->auth_failures = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700466 } else {
467 wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
468 "received credential");
469 ssid = wpa_config_add_network(wpa_s->conf);
470 if (ssid == NULL)
471 return -1;
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -0700472 if (wpa_s->current_ssid) {
473 /*
474 * Should the GO issue multiple credentials for some
475 * reason, each credential should be marked as a
476 * temporary P2P group similarly to the one that gets
477 * marked as such based on the pre-configured values
478 * used for the WPS network block.
479 */
480 ssid->p2p_group = wpa_s->current_ssid->p2p_group;
481 ssid->temporary = wpa_s->current_ssid->temporary;
482 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700483 wpas_notify_network_added(wpa_s, ssid);
484 }
485
486 wpa_config_set_network_defaults(ssid);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -0700487 ssid->wps_run = wpa_s->wps_run;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700488
489 os_free(ssid->ssid);
490 ssid->ssid = os_malloc(cred->ssid_len);
491 if (ssid->ssid) {
492 os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len);
493 ssid->ssid_len = cred->ssid_len;
494 }
495
496 switch (cred->encr_type) {
497 case WPS_ENCR_NONE:
498 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700499 case WPS_ENCR_TKIP:
Hai Shalomb755a2a2020-04-23 21:49:02 -0700500 ssid->pairwise_cipher = WPA_CIPHER_TKIP | WPA_CIPHER_CCMP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700501 break;
502 case WPS_ENCR_AES:
503 ssid->pairwise_cipher = WPA_CIPHER_CCMP;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800504 if (wpa_s->drv_capa_known &&
505 (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP)) {
506 ssid->pairwise_cipher |= WPA_CIPHER_GCMP;
507 ssid->group_cipher |= WPA_CIPHER_GCMP;
508 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700509 if (wpa_s->drv_capa_known &&
510 (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP_256)) {
511 ssid->pairwise_cipher |= WPA_CIPHER_GCMP_256;
512 ssid->group_cipher |= WPA_CIPHER_GCMP_256;
513 }
514 if (wpa_s->drv_capa_known &&
515 (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_CCMP_256)) {
516 ssid->pairwise_cipher |= WPA_CIPHER_CCMP_256;
517 ssid->group_cipher |= WPA_CIPHER_CCMP_256;
518 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700519 break;
520 }
521
522 switch (auth_type) {
523 case WPS_AUTH_OPEN:
524 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
525 ssid->key_mgmt = WPA_KEY_MGMT_NONE;
526 ssid->proto = 0;
527#ifdef CONFIG_WPS_REG_DISABLE_OPEN
528 if (registrar) {
529 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OPEN_NETWORK
530 "id=%d - Credentials for an open "
531 "network disabled by default - use "
532 "'select_network %d' to enable",
533 ssid->id, ssid->id);
534 ssid->disabled = 1;
535 }
536#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
537 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700538 case WPS_AUTH_WPAPSK:
539 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
540 ssid->key_mgmt = WPA_KEY_MGMT_PSK;
Hai Shalomb755a2a2020-04-23 21:49:02 -0700541 ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700542 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700543 case WPS_AUTH_WPA2PSK:
544 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
545 ssid->key_mgmt = WPA_KEY_MGMT_PSK;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800546 add_sae = wpa_s->conf->wps_cred_add_sae;
547#ifdef CONFIG_P2P
548 if (ssid->p2p_group && is_p2p_6ghz_capable(wpa_s->global->p2p))
549 add_sae = true;
550#endif /* CONFIG_P2P */
551 if (add_sae && cred->key_len != 2 * PMK_LEN) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700552 ssid->auth_alg = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -0700553 ssid->key_mgmt |= WPA_KEY_MGMT_SAE;
Hai Shalom021b0b52019-04-10 11:17:58 -0700554 ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
Hai Shalom021b0b52019-04-10 11:17:58 -0700555 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700556 ssid->proto = WPA_PROTO_RSN;
557 break;
558 }
559
Hai Shalom021b0b52019-04-10 11:17:58 -0700560 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700561 if (cred->key_len == 2 * PMK_LEN) {
562 if (hexstr2bin((const char *) cred->key, ssid->psk,
563 PMK_LEN)) {
564 wpa_printf(MSG_ERROR, "WPS: Invalid Network "
565 "Key");
566 return -1;
567 }
568 ssid->psk_set = 1;
569 ssid->export_keys = 1;
570 } else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) {
571 os_free(ssid->passphrase);
572 ssid->passphrase = os_malloc(cred->key_len + 1);
573 if (ssid->passphrase == NULL)
574 return -1;
575 os_memcpy(ssid->passphrase, cred->key, cred->key_len);
576 ssid->passphrase[cred->key_len] = '\0';
577 wpa_config_update_psk(ssid);
578 ssid->export_keys = 1;
579 } else {
580 wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
581 "length %lu",
582 (unsigned long) cred->key_len);
583 return -1;
584 }
585 }
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -0700586 ssid->priority = wpa_s->conf->wps_priority;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700587
588 wpas_wps_security_workaround(wpa_s, ssid, cred);
589
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -0700590 wpas_wps_remove_dup_network(wpa_s, ssid);
591
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700592#ifndef CONFIG_NO_CONFIG_WRITE
593 if (wpa_s->conf->update_config &&
594 wpa_config_write(wpa_s->confname, wpa_s->conf)) {
595 wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration");
596 return -1;
597 }
598#endif /* CONFIG_NO_CONFIG_WRITE */
599
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -0700600 if (ssid->priority)
601 wpa_config_update_prio_list(wpa_s->conf);
602
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800603 /*
604 * Optimize the post-WPS scan based on the channel used during
605 * the provisioning in case EAP-Failure is not received.
606 */
607 wpa_s->after_wps = 5;
608 wpa_s->wps_freq = wpa_s->assoc_freq;
609
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700610 return 0;
611}
612
613
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700614static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
615 struct wps_event_m2d *m2d)
616{
617 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_M2D
618 "dev_password_id=%d config_error=%d",
619 m2d->dev_password_id, m2d->config_error);
620 wpas_notify_wps_event_m2d(wpa_s, m2d);
621#ifdef CONFIG_P2P
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800622 if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s) {
623 wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_M2D
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700624 "dev_password_id=%d config_error=%d",
625 m2d->dev_password_id, m2d->config_error);
626 }
627 if (m2d->config_error == WPS_CFG_MULTIPLE_PBC_DETECTED) {
628 /*
629 * Notify P2P from eloop timeout to avoid issues with the
630 * interface getting removed while processing a message.
631 */
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -0700632 eloop_register_timeout(0, 0, wpas_p2p_pbc_overlap_cb, wpa_s,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700633 NULL);
634 }
635#endif /* CONFIG_P2P */
636}
637
638
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700639static void wpas_wps_clear_timeout(void *eloop_ctx, void *timeout_ctx)
640{
641 struct wpa_supplicant *wpa_s = eloop_ctx;
642 wpa_printf(MSG_DEBUG, "WPS: Clear WPS network from timeout");
643 wpas_clear_wps(wpa_s);
644}
645
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700646
647static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
648 struct wps_event_fail *fail)
649{
650 if (fail->error_indication > 0 &&
651 fail->error_indication < NUM_WPS_EI_VALUES) {
652 wpa_msg(wpa_s, MSG_INFO,
653 WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
654 fail->msg, fail->config_error, fail->error_indication,
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700655 wps_ei_str(fail->error_indication));
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800656 if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s)
657 wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700658 "msg=%d config_error=%d reason=%d (%s)",
659 fail->msg, fail->config_error,
660 fail->error_indication,
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700661 wps_ei_str(fail->error_indication));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700662 } else {
663 wpa_msg(wpa_s, MSG_INFO,
664 WPS_EVENT_FAIL "msg=%d config_error=%d",
665 fail->msg, fail->config_error);
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800666 if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s)
667 wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700668 "msg=%d config_error=%d",
669 fail->msg, fail->config_error);
670 }
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700671
672 /*
673 * Need to allow WPS processing to complete, e.g., by sending WSC_NACK.
674 */
675 wpa_printf(MSG_DEBUG, "WPS: Register timeout to clear WPS network");
676 eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
677 eloop_register_timeout(0, 100000, wpas_wps_clear_timeout, wpa_s, NULL);
678
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700679 wpas_notify_wps_event_fail(wpa_s, fail);
Jouni Malinen75ecf522011-06-27 15:19:46 -0700680 wpas_p2p_wps_failed(wpa_s, fail);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700681}
682
683
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800684static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx);
685
686static void wpas_wps_reenable_networks(struct wpa_supplicant *wpa_s)
687{
688 struct wpa_ssid *ssid;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800689 int changed = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800690
691 eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
692
693 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
694 if (ssid->disabled_for_connect && ssid->disabled) {
695 ssid->disabled_for_connect = 0;
696 ssid->disabled = 0;
697 wpas_notify_network_enabled_changed(wpa_s, ssid);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800698 changed++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800699 }
700 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800701
702 if (changed) {
703#ifndef CONFIG_NO_CONFIG_WRITE
704 if (wpa_s->conf->update_config &&
705 wpa_config_write(wpa_s->confname, wpa_s->conf)) {
706 wpa_printf(MSG_DEBUG, "WPS: Failed to update "
707 "configuration");
708 }
709#endif /* CONFIG_NO_CONFIG_WRITE */
710 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800711}
712
713
714static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx)
715{
716 struct wpa_supplicant *wpa_s = eloop_ctx;
717 /* Enable the networks disabled during wpas_wps_reassoc */
718 wpas_wps_reenable_networks(wpa_s);
719}
720
721
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -0800722int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s)
723{
724 return eloop_is_timeout_registered(wpas_wps_reenable_networks_cb,
725 wpa_s, NULL);
726}
727
728
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700729static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
730{
731 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
732 wpa_s->wps_success = 1;
733 wpas_notify_wps_event_success(wpa_s);
Dmitry Shmidt44c95782013-05-17 09:51:35 -0700734 if (wpa_s->current_ssid)
735 wpas_clear_temp_disabled(wpa_s, wpa_s->current_ssid, 1);
Hai Shalom899fcc72020-10-19 14:38:18 -0700736 wpa_s->consecutive_conn_failures = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800737
738 /*
739 * Enable the networks disabled during wpas_wps_reassoc after 10
740 * seconds. The 10 seconds timer is to allow the data connection to be
741 * formed before allowing other networks to be selected.
742 */
743 eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
744 NULL);
745
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700746 wpas_p2p_wps_success(wpa_s, wpa_s->bssid, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700747}
748
749
750static void wpa_supplicant_wps_event_er_ap_add(struct wpa_supplicant *wpa_s,
751 struct wps_event_er_ap *ap)
752{
753 char uuid_str[100];
754 char dev_type[WPS_DEV_TYPE_BUFSIZE];
755
756 uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str));
757 if (ap->pri_dev_type)
758 wps_dev_type_bin2str(ap->pri_dev_type, dev_type,
759 sizeof(dev_type));
760 else
761 dev_type[0] = '\0';
762
763 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_ADD "%s " MACSTR
764 " pri_dev_type=%s wps_state=%d |%s|%s|%s|%s|%s|%s|",
765 uuid_str, MAC2STR(ap->mac_addr), dev_type, ap->wps_state,
766 ap->friendly_name ? ap->friendly_name : "",
767 ap->manufacturer ? ap->manufacturer : "",
768 ap->model_description ? ap->model_description : "",
769 ap->model_name ? ap->model_name : "",
770 ap->manufacturer_url ? ap->manufacturer_url : "",
771 ap->model_url ? ap->model_url : "");
772}
773
774
775static void wpa_supplicant_wps_event_er_ap_remove(struct wpa_supplicant *wpa_s,
776 struct wps_event_er_ap *ap)
777{
778 char uuid_str[100];
779 uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str));
780 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_REMOVE "%s", uuid_str);
781}
782
783
784static void wpa_supplicant_wps_event_er_enrollee_add(
785 struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee)
786{
787 char uuid_str[100];
788 char dev_type[WPS_DEV_TYPE_BUFSIZE];
789
790 uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str));
791 if (enrollee->pri_dev_type)
792 wps_dev_type_bin2str(enrollee->pri_dev_type, dev_type,
793 sizeof(dev_type));
794 else
795 dev_type[0] = '\0';
796
797 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_ADD "%s " MACSTR
798 " M1=%d config_methods=0x%x dev_passwd_id=%d pri_dev_type=%s "
799 "|%s|%s|%s|%s|%s|",
800 uuid_str, MAC2STR(enrollee->mac_addr), enrollee->m1_received,
801 enrollee->config_methods, enrollee->dev_passwd_id, dev_type,
802 enrollee->dev_name ? enrollee->dev_name : "",
803 enrollee->manufacturer ? enrollee->manufacturer : "",
804 enrollee->model_name ? enrollee->model_name : "",
805 enrollee->model_number ? enrollee->model_number : "",
806 enrollee->serial_number ? enrollee->serial_number : "");
807}
808
809
810static void wpa_supplicant_wps_event_er_enrollee_remove(
811 struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee)
812{
813 char uuid_str[100];
814 uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str));
815 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_REMOVE "%s " MACSTR,
816 uuid_str, MAC2STR(enrollee->mac_addr));
817}
818
819
820static void wpa_supplicant_wps_event_er_ap_settings(
821 struct wpa_supplicant *wpa_s,
822 struct wps_event_er_ap_settings *ap_settings)
823{
824 char uuid_str[100];
825 char key_str[65];
826 const struct wps_credential *cred = ap_settings->cred;
827
828 key_str[0] = '\0';
829 if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
830 if (cred->key_len >= 8 && cred->key_len <= 64) {
831 os_memcpy(key_str, cred->key, cred->key_len);
832 key_str[cred->key_len] = '\0';
833 }
834 }
835
836 uuid_bin2str(ap_settings->uuid, uuid_str, sizeof(uuid_str));
837 /* Use wpa_msg_ctrl to avoid showing the key in debug log */
838 wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_SETTINGS
839 "uuid=%s ssid=%s auth_type=0x%04x encr_type=0x%04x "
840 "key=%s",
841 uuid_str, wpa_ssid_txt(cred->ssid, cred->ssid_len),
842 cred->auth_type, cred->encr_type, key_str);
843}
844
845
846static void wpa_supplicant_wps_event_er_set_sel_reg(
847 struct wpa_supplicant *wpa_s,
848 struct wps_event_er_set_selected_registrar *ev)
849{
850 char uuid_str[100];
851
852 uuid_bin2str(ev->uuid, uuid_str, sizeof(uuid_str));
853 switch (ev->state) {
854 case WPS_ER_SET_SEL_REG_START:
855 wpa_msg(wpa_s, MSG_DEBUG, WPS_EVENT_ER_SET_SEL_REG
856 "uuid=%s state=START sel_reg=%d dev_passwd_id=%u "
857 "sel_reg_config_methods=0x%x",
858 uuid_str, ev->sel_reg, ev->dev_passwd_id,
859 ev->sel_reg_config_methods);
860 break;
861 case WPS_ER_SET_SEL_REG_DONE:
862 wpa_msg(wpa_s, MSG_DEBUG, WPS_EVENT_ER_SET_SEL_REG
863 "uuid=%s state=DONE", uuid_str);
864 break;
865 case WPS_ER_SET_SEL_REG_FAILED:
866 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_SET_SEL_REG
867 "uuid=%s state=FAILED", uuid_str);
868 break;
869 }
870}
871
872
873static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
874 union wps_event_data *data)
875{
876 struct wpa_supplicant *wpa_s = ctx;
877 switch (event) {
878 case WPS_EV_M2D:
879 wpa_supplicant_wps_event_m2d(wpa_s, &data->m2d);
880 break;
881 case WPS_EV_FAIL:
882 wpa_supplicant_wps_event_fail(wpa_s, &data->fail);
883 break;
884 case WPS_EV_SUCCESS:
885 wpa_supplicant_wps_event_success(wpa_s);
886 break;
887 case WPS_EV_PWD_AUTH_FAIL:
888#ifdef CONFIG_AP
889 if (wpa_s->ap_iface && data->pwd_auth_fail.enrollee)
890 wpa_supplicant_ap_pwd_auth_fail(wpa_s);
891#endif /* CONFIG_AP */
892 break;
893 case WPS_EV_PBC_OVERLAP:
894 break;
895 case WPS_EV_PBC_TIMEOUT:
896 break;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700897 case WPS_EV_PBC_ACTIVE:
898 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ACTIVE);
899 break;
900 case WPS_EV_PBC_DISABLE:
901 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_DISABLE);
902 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700903 case WPS_EV_ER_AP_ADD:
904 wpa_supplicant_wps_event_er_ap_add(wpa_s, &data->ap);
905 break;
906 case WPS_EV_ER_AP_REMOVE:
907 wpa_supplicant_wps_event_er_ap_remove(wpa_s, &data->ap);
908 break;
909 case WPS_EV_ER_ENROLLEE_ADD:
910 wpa_supplicant_wps_event_er_enrollee_add(wpa_s,
911 &data->enrollee);
912 break;
913 case WPS_EV_ER_ENROLLEE_REMOVE:
914 wpa_supplicant_wps_event_er_enrollee_remove(wpa_s,
915 &data->enrollee);
916 break;
917 case WPS_EV_ER_AP_SETTINGS:
918 wpa_supplicant_wps_event_er_ap_settings(wpa_s,
919 &data->ap_settings);
920 break;
921 case WPS_EV_ER_SET_SELECTED_REGISTRAR:
922 wpa_supplicant_wps_event_er_set_sel_reg(wpa_s,
923 &data->set_sel_reg);
924 break;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800925 case WPS_EV_AP_PIN_SUCCESS:
926 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700927 }
928}
929
930
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700931static int wpa_supplicant_wps_rf_band(void *ctx)
932{
933 struct wpa_supplicant *wpa_s = ctx;
934
935 if (!wpa_s->current_ssid || !wpa_s->assoc_freq)
936 return 0;
937
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700938 return (wpa_s->assoc_freq > 50000) ? WPS_RF_60GHZ :
939 (wpa_s->assoc_freq > 2484) ? WPS_RF_50GHZ : WPS_RF_24GHZ;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700940}
941
942
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700943enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid)
944{
945 if (eap_is_wps_pbc_enrollee(&ssid->eap) ||
946 eap_is_wps_pin_enrollee(&ssid->eap))
947 return WPS_REQ_ENROLLEE;
948 else
949 return WPS_REQ_REGISTRAR;
950}
951
952
953static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
954{
955 int id;
Jouni Malinen75ecf522011-06-27 15:19:46 -0700956 struct wpa_ssid *ssid, *remove_ssid = NULL, *prev_current;
957
Dmitry Shmidt051af732013-10-22 13:52:46 -0700958 wpa_s->after_wps = 0;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700959 wpa_s->known_wps_freq = 0;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700960
Jouni Malinen75ecf522011-06-27 15:19:46 -0700961 prev_current = wpa_s->current_ssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700962
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800963 /* Enable the networks disabled during wpas_wps_reassoc */
964 wpas_wps_reenable_networks(wpa_s);
965
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700966 eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800967 eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700968
969 /* Remove any existing WPS network from configuration */
970 ssid = wpa_s->conf->ssid;
971 while (ssid) {
972 if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
973 if (ssid == wpa_s->current_ssid) {
Dmitry Shmidt203eadb2015-03-05 14:16:04 -0800974 wpa_s->own_disconnect_req = 1;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700975 wpa_supplicant_deauthenticate(
976 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700977 }
978 id = ssid->id;
979 remove_ssid = ssid;
980 } else
981 id = -1;
982 ssid = ssid->next;
983 if (id >= 0) {
Jouni Malinen75ecf522011-06-27 15:19:46 -0700984 if (prev_current == remove_ssid) {
985 wpa_sm_set_config(wpa_s->wpa, NULL);
986 eapol_sm_notify_config(wpa_s->eapol, NULL,
987 NULL);
988 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700989 wpas_notify_network_removed(wpa_s, remove_ssid);
990 wpa_config_remove_network(wpa_s->conf, id);
991 }
992 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700993
994 wpas_wps_clear_ap_info(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700995}
996
997
998static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
999{
1000 struct wpa_supplicant *wpa_s = eloop_ctx;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001001 union wps_event_data data;
1002
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001003 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed "
1004 "out");
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001005 os_memset(&data, 0, sizeof(data));
1006 data.fail.config_error = WPS_CFG_MSG_TIMEOUT;
1007 data.fail.error_indication = WPS_EI_NO_ERROR;
1008 /*
1009 * Call wpas_notify_wps_event_fail() directly instead of through
1010 * wpa_supplicant_wps_event() which would end up registering unnecessary
1011 * timeouts (those are only for the case where the failure happens
1012 * during an EAP-WSC exchange).
1013 */
1014 wpas_notify_wps_event_fail(wpa_s, &data.fail);
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001015 wpa_s->supp_pbc_active = false;
Sunil Raviaf8751c2023-03-29 11:35:17 -07001016 wpa_s->wps_overlap = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001017 wpas_clear_wps(wpa_s);
1018}
1019
1020
1021static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001022 int registrar, const u8 *dev_addr,
1023 const u8 *bssid)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001024{
1025 struct wpa_ssid *ssid;
1026
1027 ssid = wpa_config_add_network(wpa_s->conf);
1028 if (ssid == NULL)
1029 return NULL;
1030 wpas_notify_network_added(wpa_s, ssid);
1031 wpa_config_set_network_defaults(ssid);
1032 ssid->temporary = 1;
1033 if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 ||
1034 wpa_config_set(ssid, "eap", "WSC", 0) < 0 ||
1035 wpa_config_set(ssid, "identity", registrar ?
1036 "\"" WSC_ID_REGISTRAR "\"" :
1037 "\"" WSC_ID_ENROLLEE "\"", 0) < 0) {
1038 wpas_notify_network_removed(wpa_s, ssid);
1039 wpa_config_remove_network(wpa_s->conf, ssid->id);
1040 return NULL;
1041 }
1042
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001043#ifdef CONFIG_P2P
1044 if (dev_addr)
1045 os_memcpy(ssid->go_p2p_dev_addr, dev_addr, ETH_ALEN);
1046#endif /* CONFIG_P2P */
1047
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001048 if (bssid) {
1049#ifndef CONFIG_P2P
1050 struct wpa_bss *bss;
1051 int count = 0;
1052#endif /* CONFIG_P2P */
1053
1054 os_memcpy(ssid->bssid, bssid, ETH_ALEN);
1055 ssid->bssid_set = 1;
1056
1057 /*
1058 * Note: With P2P, the SSID may change at the time the WPS
1059 * provisioning is started, so better not filter the AP based
1060 * on the current SSID in the scan results.
1061 */
1062#ifndef CONFIG_P2P
1063 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001064 if (!ether_addr_equal(bssid, bss->bssid))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001065 continue;
1066
1067 os_free(ssid->ssid);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001068 ssid->ssid = os_memdup(bss->ssid, bss->ssid_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001069 if (ssid->ssid == NULL)
1070 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001071 ssid->ssid_len = bss->ssid_len;
1072 wpa_hexdump_ascii(MSG_DEBUG, "WPS: Picked SSID from "
1073 "scan results",
1074 ssid->ssid, ssid->ssid_len);
1075 count++;
1076 }
1077
1078 if (count > 1) {
1079 wpa_printf(MSG_DEBUG, "WPS: More than one SSID found "
1080 "for the AP; use wildcard");
1081 os_free(ssid->ssid);
1082 ssid->ssid = NULL;
1083 ssid->ssid_len = 0;
1084 }
1085#endif /* CONFIG_P2P */
1086 }
1087
1088 return ssid;
1089}
1090
1091
Dmitry Shmidt44c95782013-05-17 09:51:35 -07001092static void wpas_wps_temp_disable(struct wpa_supplicant *wpa_s,
1093 struct wpa_ssid *selected)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001094{
1095 struct wpa_ssid *ssid;
1096
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001097 if (wpa_s->current_ssid) {
1098 wpa_s->own_disconnect_req = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001099 wpa_supplicant_deauthenticate(
1100 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001101 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001102
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001103 /* Mark all other networks disabled and trigger reassociation */
1104 ssid = wpa_s->conf->ssid;
1105 while (ssid) {
1106 int was_disabled = ssid->disabled;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001107 ssid->disabled_for_connect = 0;
Jouni Malinen75ecf522011-06-27 15:19:46 -07001108 /*
1109 * In case the network object corresponds to a persistent group
1110 * then do not send out network disabled signal. In addition,
1111 * do not change disabled status of persistent network objects
1112 * from 2 to 1 should we connect to another network.
1113 */
1114 if (was_disabled != 2) {
1115 ssid->disabled = ssid != selected;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001116 if (was_disabled != ssid->disabled) {
1117 if (ssid->disabled)
1118 ssid->disabled_for_connect = 1;
Jouni Malinen75ecf522011-06-27 15:19:46 -07001119 wpas_notify_network_enabled_changed(wpa_s,
1120 ssid);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001121 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07001122 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001123 ssid = ssid->next;
1124 }
Dmitry Shmidt44c95782013-05-17 09:51:35 -07001125}
1126
1127
1128static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001129 struct wpa_ssid *selected, const u8 *bssid,
1130 int freq)
Dmitry Shmidt44c95782013-05-17 09:51:35 -07001131{
1132 struct wpa_bss *bss;
1133
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001134 wpa_s->wps_run++;
1135 if (wpa_s->wps_run == 0)
1136 wpa_s->wps_run++;
Dmitry Shmidt44c95782013-05-17 09:51:35 -07001137 wpa_s->after_wps = 0;
1138 wpa_s->known_wps_freq = 0;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001139 if (freq) {
1140 wpa_s->after_wps = 5;
1141 wpa_s->wps_freq = freq;
1142 } else if (bssid) {
Dmitry Shmidt44c95782013-05-17 09:51:35 -07001143 bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
1144 if (bss && bss->freq > 0) {
1145 wpa_s->known_wps_freq = 1;
1146 wpa_s->wps_freq = bss->freq;
1147 }
1148 }
1149
1150 wpas_wps_temp_disable(wpa_s, selected);
1151
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001152 wpa_s->disconnected = 0;
1153 wpa_s->reassociate = 1;
1154 wpa_s->scan_runs = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001155 wpa_s->normal_scans = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001156 wpa_s->wps_success = 0;
Hai Shalom60840252021-02-19 19:02:11 -08001157 wpa_s->bssid_ignore_cleared = false;
Dmitry Shmidtfa3fc4a2013-11-21 13:34:38 -08001158
1159 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001160 wpa_supplicant_req_scan(wpa_s, 0, 0);
1161}
1162
1163
1164int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
Hai Shalom021b0b52019-04-10 11:17:58 -07001165 int p2p_group, int multi_ap_backhaul_sta)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001166{
1167 struct wpa_ssid *ssid;
Hai Shalom021b0b52019-04-10 11:17:58 -07001168 char phase1[32];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001169
1170#ifdef CONFIG_AP
1171 if (wpa_s->ap_iface) {
1172 wpa_printf(MSG_DEBUG,
1173 "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
1174 return -1;
1175 }
1176#endif /* CONFIG_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001177 wpas_clear_wps(wpa_s);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001178 ssid = wpas_wps_add_network(wpa_s, 0, NULL, bssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001179 if (ssid == NULL)
1180 return -1;
1181 ssid->temporary = 1;
1182 ssid->p2p_group = p2p_group;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07001183 /*
1184 * When starting a regular WPS process (not P2P group formation)
1185 * the registrar/final station can be either AP or PCP
1186 * so use a "don't care" value for the pbss flag.
1187 */
1188 if (!p2p_group)
1189 ssid->pbss = 2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001190#ifdef CONFIG_P2P
1191 if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
1192 ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
1193 if (ssid->ssid) {
1194 ssid->ssid_len = wpa_s->go_params->ssid_len;
1195 os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
1196 ssid->ssid_len);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001197 if (wpa_s->go_params->freq > 56160) {
1198 /* P2P in 60 GHz uses PBSS */
1199 ssid->pbss = 1;
1200 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001201 if (wpa_s->go_params->edmg &&
1202 wpas_p2p_try_edmg_channel(wpa_s,
1203 wpa_s->go_params) == 0)
1204 ssid->enable_edmg = 1;
1205
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001206 wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
1207 "SSID", ssid->ssid, ssid->ssid_len);
1208 }
1209 }
1210#endif /* CONFIG_P2P */
Sunil Ravi88611412024-06-28 17:34:56 +00001211 os_snprintf(phase1, sizeof(phase1), "pbc=1%s",
1212 multi_ap_backhaul_sta ? " multi_ap=1" : "");
Hai Shalom021b0b52019-04-10 11:17:58 -07001213 if (wpa_config_set_quoted(ssid, "phase1", phase1) < 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001214 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001215 if (wpa_s->wps_fragment_size)
1216 ssid->eap.fragment_size = wpa_s->wps_fragment_size;
Sunil Ravi88611412024-06-28 17:34:56 +00001217 if (multi_ap_backhaul_sta)
Hai Shalom021b0b52019-04-10 11:17:58 -07001218 ssid->multi_ap_backhaul_sta = 1;
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001219 wpa_s->supp_pbc_active = true;
1220 wpa_s->wps_overlap = false;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001221 wpa_supplicant_wps_event(wpa_s, WPS_EV_PBC_ACTIVE, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001222 eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
1223 wpa_s, NULL);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001224 wpas_wps_reassoc(wpa_s, ssid, bssid, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001225 return 0;
1226}
1227
1228
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001229static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
1230 const u8 *dev_addr, const u8 *bssid,
1231 const char *pin, int p2p_group, u16 dev_pw_id,
1232 const u8 *peer_pubkey_hash,
1233 const u8 *ssid_val, size_t ssid_len, int freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001234{
1235 struct wpa_ssid *ssid;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001236 char val[128 + 2 * WPS_OOB_PUBKEY_HASH_LEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001237 unsigned int rpin = 0;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001238 char hash[2 * WPS_OOB_PUBKEY_HASH_LEN + 10];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001239
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001240#ifdef CONFIG_AP
1241 if (wpa_s->ap_iface) {
1242 wpa_printf(MSG_DEBUG,
1243 "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
1244 return -1;
1245 }
1246#endif /* CONFIG_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001247 wpas_clear_wps(wpa_s);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001248 if (bssid && is_zero_ether_addr(bssid))
1249 bssid = NULL;
1250 ssid = wpas_wps_add_network(wpa_s, 0, dev_addr, bssid);
1251 if (ssid == NULL) {
1252 wpa_printf(MSG_DEBUG, "WPS: Could not add network");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001253 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001254 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001255 ssid->temporary = 1;
1256 ssid->p2p_group = p2p_group;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07001257 /*
1258 * When starting a regular WPS process (not P2P group formation)
1259 * the registrar/final station can be either AP or PCP
1260 * so use a "don't care" value for the pbss flag.
1261 */
1262 if (!p2p_group)
1263 ssid->pbss = 2;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001264 if (ssid_val) {
1265 ssid->ssid = os_malloc(ssid_len);
1266 if (ssid->ssid) {
1267 os_memcpy(ssid->ssid, ssid_val, ssid_len);
1268 ssid->ssid_len = ssid_len;
1269 }
1270 }
1271 if (peer_pubkey_hash) {
1272 os_memcpy(hash, " pkhash=", 8);
1273 wpa_snprintf_hex_uppercase(hash + 8, sizeof(hash) - 8,
1274 peer_pubkey_hash,
1275 WPS_OOB_PUBKEY_HASH_LEN);
1276 } else {
1277 hash[0] = '\0';
1278 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001279#ifdef CONFIG_P2P
1280 if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
Dmitry Shmidtb1e52102015-05-29 12:36:29 -07001281 os_free(ssid->ssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001282 ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
1283 if (ssid->ssid) {
1284 ssid->ssid_len = wpa_s->go_params->ssid_len;
1285 os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
1286 ssid->ssid_len);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001287 if (wpa_s->go_params->freq > 56160) {
1288 /* P2P in 60 GHz uses PBSS */
1289 ssid->pbss = 1;
1290 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001291 if (wpa_s->go_params->edmg &&
1292 wpas_p2p_try_edmg_channel(wpa_s,
1293 wpa_s->go_params) == 0)
1294 ssid->enable_edmg = 1;
1295
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001296 wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
1297 "SSID", ssid->ssid, ssid->ssid_len);
1298 }
1299 }
1300#endif /* CONFIG_P2P */
1301 if (pin)
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001302 os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u%s\"",
1303 pin, dev_pw_id, hash);
1304 else if (pin == NULL && dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) {
1305 os_snprintf(val, sizeof(val), "\"dev_pw_id=%u%s\"",
1306 dev_pw_id, hash);
1307 } else {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001308 if (wps_generate_pin(&rpin) < 0) {
1309 wpa_printf(MSG_DEBUG, "WPS: Could not generate PIN");
1310 return -1;
1311 }
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001312 os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u%s\"",
1313 rpin, dev_pw_id, hash);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001314 }
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001315 if (wpa_config_set(ssid, "phase1", val, 0) < 0) {
1316 wpa_printf(MSG_DEBUG, "WPS: Failed to set phase1 '%s'", val);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001317 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001318 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001319
1320 if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER)
1321 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_PIN_ACTIVE);
1322
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001323 if (wpa_s->wps_fragment_size)
1324 ssid->eap.fragment_size = wpa_s->wps_fragment_size;
1325 eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
1326 wpa_s, NULL);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001327 wpa_s->wps_ap_iter = 1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001328 wpas_wps_reassoc(wpa_s, ssid, bssid, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001329 return rpin;
1330}
1331
1332
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001333int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
1334 const char *pin, int p2p_group, u16 dev_pw_id)
1335{
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001336 os_get_reltime(&wpa_s->wps_pin_start_time);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001337 return wpas_wps_start_dev_pw(wpa_s, NULL, bssid, pin, p2p_group,
1338 dev_pw_id, NULL, NULL, 0, 0);
1339}
1340
1341
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001342void wpas_wps_pbc_overlap(struct wpa_supplicant *wpa_s)
1343{
1344 union wps_event_data data;
1345
1346 os_memset(&data, 0, sizeof(data));
1347 data.fail.config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
1348 data.fail.error_indication = WPS_EI_NO_ERROR;
1349 /*
1350 * Call wpas_notify_wps_event_fail() directly instead of through
1351 * wpa_supplicant_wps_event() which would end up registering unnecessary
1352 * timeouts (those are only for the case where the failure happens
1353 * during an EAP-WSC exchange).
1354 */
1355 wpas_notify_wps_event_fail(wpa_s, &data.fail);
1356}
1357
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001358/* Cancel the wps pbc/pin requests */
1359int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
1360{
1361#ifdef CONFIG_AP
1362 if (wpa_s->ap_iface) {
1363 wpa_printf(MSG_DEBUG, "WPS: Cancelling in AP mode");
1364 return wpa_supplicant_ap_wps_cancel(wpa_s);
1365 }
1366#endif /* CONFIG_AP */
1367
Dmitry Shmidt04949592012-07-19 12:16:46 -07001368 if (wpa_s->wpa_state == WPA_SCANNING ||
1369 wpa_s->wpa_state == WPA_DISCONNECTED) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001370 wpa_printf(MSG_DEBUG, "WPS: Cancel operation - cancel scan");
1371 wpa_supplicant_cancel_scan(wpa_s);
1372 wpas_clear_wps(wpa_s);
1373 } else if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
1374 wpa_printf(MSG_DEBUG, "WPS: Cancel operation - "
1375 "deauthenticate");
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001376 wpa_s->own_disconnect_req = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001377 wpa_supplicant_deauthenticate(wpa_s,
1378 WLAN_REASON_DEAUTH_LEAVING);
1379 wpas_clear_wps(wpa_s);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001380 } else {
1381 wpas_wps_reenable_networks(wpa_s);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001382 wpas_wps_clear_ap_info(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001383 if (eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL) >
1384 0)
1385 wpas_clear_wps(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001386 }
1387
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001388 wpa_s->supp_pbc_active = false;
Sunil Raviaf8751c2023-03-29 11:35:17 -07001389 wpa_s->wps_overlap = false;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001390 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CANCEL);
Dmitry Shmidt051af732013-10-22 13:52:46 -07001391 wpa_s->after_wps = 0;
1392
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001393 return 0;
1394}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001395
1396
1397int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
1398 const char *pin, struct wps_new_ap_settings *settings)
1399{
1400 struct wpa_ssid *ssid;
1401 char val[200];
1402 char *pos, *end;
1403 int res;
1404
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001405#ifdef CONFIG_AP
1406 if (wpa_s->ap_iface) {
1407 wpa_printf(MSG_DEBUG,
1408 "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
1409 return -1;
1410 }
1411#endif /* CONFIG_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001412 if (!pin)
1413 return -1;
1414 wpas_clear_wps(wpa_s);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001415 ssid = wpas_wps_add_network(wpa_s, 1, NULL, bssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001416 if (ssid == NULL)
1417 return -1;
1418 ssid->temporary = 1;
1419 pos = val;
1420 end = pos + sizeof(val);
1421 res = os_snprintf(pos, end - pos, "\"pin=%s", pin);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001422 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001423 return -1;
1424 pos += res;
1425 if (settings) {
1426 res = os_snprintf(pos, end - pos, " new_ssid=%s new_auth=%s "
1427 "new_encr=%s new_key=%s",
1428 settings->ssid_hex, settings->auth,
1429 settings->encr, settings->key_hex);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001430 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001431 return -1;
1432 pos += res;
1433 }
1434 res = os_snprintf(pos, end - pos, "\"");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001435 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001436 return -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001437 if (wpa_config_set(ssid, "phase1", val, 0) < 0)
1438 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001439 if (wpa_s->wps_fragment_size)
1440 ssid->eap.fragment_size = wpa_s->wps_fragment_size;
1441 eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
1442 wpa_s, NULL);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001443 wpas_wps_reassoc(wpa_s, ssid, bssid, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001444 return 0;
1445}
1446
1447
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001448static int wpas_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
1449 const u8 *p2p_dev_addr, const u8 *psk,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001450 size_t psk_len)
1451{
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001452 if (is_zero_ether_addr(p2p_dev_addr)) {
1453 wpa_printf(MSG_DEBUG,
1454 "Received new WPA/WPA2-PSK from WPS for STA " MACSTR,
1455 MAC2STR(mac_addr));
1456 } else {
1457 wpa_printf(MSG_DEBUG,
1458 "Received new WPA/WPA2-PSK from WPS for STA " MACSTR
1459 " P2P Device Addr " MACSTR,
1460 MAC2STR(mac_addr), MAC2STR(p2p_dev_addr));
1461 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001462 wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
1463
1464 /* TODO */
1465
1466 return 0;
1467}
1468
1469
1470static void wpas_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
1471 const struct wps_device_data *dev)
1472{
1473 char uuid[40], txt[400];
1474 int len;
1475 char devtype[WPS_DEV_TYPE_BUFSIZE];
1476 if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
1477 return;
1478 wpa_printf(MSG_DEBUG, "WPS: PIN needed for UUID-E %s", uuid);
1479 len = os_snprintf(txt, sizeof(txt), "WPS-EVENT-PIN-NEEDED %s " MACSTR
1480 " [%s|%s|%s|%s|%s|%s]",
1481 uuid, MAC2STR(dev->mac_addr), dev->device_name,
1482 dev->manufacturer, dev->model_name,
1483 dev->model_number, dev->serial_number,
1484 wps_dev_type_bin2str(dev->pri_dev_type, devtype,
1485 sizeof(devtype)));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001486 if (!os_snprintf_error(sizeof(txt), len))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001487 wpa_printf(MSG_INFO, "%s", txt);
1488}
1489
1490
1491static void wpas_wps_set_sel_reg_cb(void *ctx, int sel_reg, u16 dev_passwd_id,
1492 u16 sel_reg_config_methods)
1493{
1494#ifdef CONFIG_WPS_ER
1495 struct wpa_supplicant *wpa_s = ctx;
1496
1497 if (wpa_s->wps_er == NULL)
1498 return;
1499 wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar - sel_reg=%d "
1500 "dev_password_id=%u sel_reg_config_methods=0x%x",
1501 sel_reg, dev_passwd_id, sel_reg_config_methods);
1502 wps_er_set_sel_reg(wpa_s->wps_er, sel_reg, dev_passwd_id,
1503 sel_reg_config_methods);
1504#endif /* CONFIG_WPS_ER */
1505}
1506
1507
1508static u16 wps_fix_config_methods(u16 config_methods)
1509{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001510 if ((config_methods &
1511 (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY |
1512 WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) {
1513 wpa_printf(MSG_INFO, "WPS: Converting display to "
1514 "virtual_display for WPS 2.0 compliance");
1515 config_methods |= WPS_CONFIG_VIRT_DISPLAY;
1516 }
1517 if ((config_methods &
1518 (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON |
1519 WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) {
1520 wpa_printf(MSG_INFO, "WPS: Converting push_button to "
1521 "virtual_push_button for WPS 2.0 compliance");
1522 config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
1523 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001524
1525 return config_methods;
1526}
1527
1528
1529static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
1530 struct wps_context *wps)
1531{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001532 char buf[50];
1533 const char *src;
1534
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001535 if (is_nil_uuid(wpa_s->conf->uuid)) {
1536 struct wpa_supplicant *first;
1537 first = wpa_s->global->ifaces;
1538 while (first && first->next)
1539 first = first->next;
1540 if (first && first != wpa_s) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001541 if (wps != wpa_s->global->ifaces->wps)
1542 os_memcpy(wps->uuid,
1543 wpa_s->global->ifaces->wps->uuid,
1544 WPS_UUID_LEN);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001545 src = "from the first interface";
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001546 } else if (wpa_s->conf->auto_uuid == 1) {
1547 uuid_random(wps->uuid);
1548 src = "based on random data";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001549 } else {
1550 uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001551 src = "based on MAC address";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001552 }
1553 } else {
1554 os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001555 src = "based on configuration";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001556 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001557
1558 uuid_bin2str(wps->uuid, buf, sizeof(buf));
1559 wpa_dbg(wpa_s, MSG_DEBUG, "WPS: UUID %s: %s", src, buf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001560}
1561
1562
Dmitry Shmidt04949592012-07-19 12:16:46 -07001563static void wpas_wps_set_vendor_ext_m1(struct wpa_supplicant *wpa_s,
1564 struct wps_context *wps)
1565{
1566 wpabuf_free(wps->dev.vendor_ext_m1);
1567 wps->dev.vendor_ext_m1 = NULL;
1568
1569 if (wpa_s->conf->wps_vendor_ext_m1) {
1570 wps->dev.vendor_ext_m1 =
1571 wpabuf_dup(wpa_s->conf->wps_vendor_ext_m1);
1572 if (!wps->dev.vendor_ext_m1) {
1573 wpa_printf(MSG_ERROR, "WPS: Cannot "
1574 "allocate memory for vendor_ext_m1");
1575 }
1576 }
1577}
1578
1579
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001580int wpas_wps_init(struct wpa_supplicant *wpa_s)
1581{
1582 struct wps_context *wps;
1583 struct wps_registrar_config rcfg;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001584 struct hostapd_hw_modes *modes;
1585 u16 m;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001586
1587 wps = os_zalloc(sizeof(*wps));
1588 if (wps == NULL)
1589 return -1;
1590
1591 wps->cred_cb = wpa_supplicant_wps_cred;
1592 wps->event_cb = wpa_supplicant_wps_event;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07001593 wps->rf_band_cb = wpa_supplicant_wps_rf_band;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001594 wps->cb_ctx = wpa_s;
1595
1596 wps->dev.device_name = wpa_s->conf->device_name;
1597 wps->dev.manufacturer = wpa_s->conf->manufacturer;
1598 wps->dev.model_name = wpa_s->conf->model_name;
1599 wps->dev.model_number = wpa_s->conf->model_number;
1600 wps->dev.serial_number = wpa_s->conf->serial_number;
1601 wps->config_methods =
1602 wps_config_methods_str2bin(wpa_s->conf->config_methods);
1603 if ((wps->config_methods & (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) ==
1604 (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) {
1605 wpa_printf(MSG_ERROR, "WPS: Both Label and Display config "
1606 "methods are not allowed at the same time");
1607 os_free(wps);
1608 return -1;
1609 }
1610 wps->config_methods = wps_fix_config_methods(wps->config_methods);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001611 wps->dev.config_methods = wps->config_methods;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001612 os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type,
1613 WPS_DEV_TYPE_LEN);
1614
1615 wps->dev.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
1616 os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type,
1617 WPS_DEV_TYPE_LEN * wps->dev.num_sec_dev_types);
1618
Dmitry Shmidt04949592012-07-19 12:16:46 -07001619 wpas_wps_set_vendor_ext_m1(wpa_s, wps);
1620
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001621 wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001622 modes = wpa_s->hw.modes;
1623 if (modes) {
1624 for (m = 0; m < wpa_s->hw.num_modes; m++) {
1625 if (modes[m].mode == HOSTAPD_MODE_IEEE80211B ||
1626 modes[m].mode == HOSTAPD_MODE_IEEE80211G)
1627 wps->dev.rf_bands |= WPS_RF_24GHZ;
1628 else if (modes[m].mode == HOSTAPD_MODE_IEEE80211A)
1629 wps->dev.rf_bands |= WPS_RF_50GHZ;
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001630 else if (modes[m].mode == HOSTAPD_MODE_IEEE80211AD)
1631 wps->dev.rf_bands |= WPS_RF_60GHZ;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001632 }
1633 }
1634 if (wps->dev.rf_bands == 0) {
1635 /*
1636 * Default to claiming support for both bands if the driver
1637 * does not provide support for fetching supported bands.
1638 */
1639 wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ;
1640 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001641 os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
1642 wpas_wps_set_uuid(wpa_s, wps);
1643
Hai Shalomb755a2a2020-04-23 21:49:02 -07001644#ifdef CONFIG_NO_TKIP
1645 wps->auth_types = WPS_AUTH_WPA2PSK;
1646 wps->encr_types = WPS_ENCR_AES;
1647#else /* CONFIG_NO_TKIP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001648 wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
1649 wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
Hai Shalomb755a2a2020-04-23 21:49:02 -07001650#endif /* CONFIG_NO_TKIP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001651
1652 os_memset(&rcfg, 0, sizeof(rcfg));
1653 rcfg.new_psk_cb = wpas_wps_new_psk_cb;
1654 rcfg.pin_needed_cb = wpas_wps_pin_needed_cb;
1655 rcfg.set_sel_reg_cb = wpas_wps_set_sel_reg_cb;
1656 rcfg.cb_ctx = wpa_s;
1657
1658 wps->registrar = wps_registrar_init(wps, &rcfg);
1659 if (wps->registrar == NULL) {
1660 wpa_printf(MSG_DEBUG, "Failed to initialize WPS Registrar");
1661 os_free(wps);
1662 return -1;
1663 }
1664
1665 wpa_s->wps = wps;
1666
1667 return 0;
1668}
1669
1670
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001671#ifdef CONFIG_WPS_ER
1672static void wpas_wps_nfc_clear(struct wps_context *wps)
1673{
1674 wps->ap_nfc_dev_pw_id = 0;
1675 wpabuf_free(wps->ap_nfc_dh_pubkey);
1676 wps->ap_nfc_dh_pubkey = NULL;
1677 wpabuf_free(wps->ap_nfc_dh_privkey);
1678 wps->ap_nfc_dh_privkey = NULL;
1679 wpabuf_free(wps->ap_nfc_dev_pw);
1680 wps->ap_nfc_dev_pw = NULL;
1681}
1682#endif /* CONFIG_WPS_ER */
1683
1684
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001685void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
1686{
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07001687 wpas_wps_assoc_with_cred_cancel(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001688 eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07001689 eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001690 eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001691 wpas_wps_clear_ap_info(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001692
Dmitry Shmidt684785c2014-05-12 13:34:29 -07001693#ifdef CONFIG_P2P
1694 eloop_cancel_timeout(wpas_p2p_pbc_overlap_cb, wpa_s, NULL);
1695#endif /* CONFIG_P2P */
1696
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001697 if (wpa_s->wps == NULL)
1698 return;
1699
1700#ifdef CONFIG_WPS_ER
1701 wps_er_deinit(wpa_s->wps_er, NULL, NULL);
1702 wpa_s->wps_er = NULL;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001703 wpas_wps_nfc_clear(wpa_s->wps);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001704#endif /* CONFIG_WPS_ER */
1705
1706 wps_registrar_deinit(wpa_s->wps->registrar);
1707 wpabuf_free(wpa_s->wps->dh_pubkey);
1708 wpabuf_free(wpa_s->wps->dh_privkey);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001709 wpabuf_free(wpa_s->wps->dev.vendor_ext_m1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001710 os_free(wpa_s->wps->network_key);
1711 os_free(wpa_s->wps);
1712 wpa_s->wps = NULL;
1713}
1714
1715
1716int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -07001717 struct wpa_ssid *ssid, struct wpa_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001718{
1719 struct wpabuf *wps_ie;
1720
1721 if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
1722 return -1;
1723
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001724 wps_ie = wpas_wps_get_wps_ie(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001725 if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
1726 if (!wps_ie) {
1727 wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
1728 return 0;
1729 }
1730
1731 if (!wps_is_selected_pbc_registrar(wps_ie)) {
1732 wpa_printf(MSG_DEBUG, " skip - WPS AP "
1733 "without active PBC Registrar");
1734 wpabuf_free(wps_ie);
1735 return 0;
1736 }
1737
1738 /* TODO: overlap detection */
1739 wpa_printf(MSG_DEBUG, " selected based on WPS IE "
1740 "(Active PBC)");
1741 wpabuf_free(wps_ie);
1742 return 1;
1743 }
1744
1745 if (eap_is_wps_pin_enrollee(&ssid->eap)) {
1746 if (!wps_ie) {
1747 wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
1748 return 0;
1749 }
1750
1751 /*
1752 * Start with WPS APs that advertise our address as an
1753 * authorized MAC (v2.0) or active PIN Registrar (v1.0) and
1754 * allow any WPS AP after couple of scans since some APs do not
1755 * set Selected Registrar attribute properly when using
1756 * external Registrar.
1757 */
1758 if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001759 struct os_reltime age;
1760
1761 os_reltime_age(&wpa_s->wps_pin_start_time, &age);
1762
1763 if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG ||
1764 age.sec < WPS_PIN_TIME_IGNORE_SEL_REG) {
1765 wpa_printf(MSG_DEBUG,
1766 " skip - WPS AP without active PIN Registrar (scan_runs=%d age=%d)",
1767 wpa_s->scan_runs, (int) age.sec);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001768 wpabuf_free(wps_ie);
1769 return 0;
1770 }
1771 wpa_printf(MSG_DEBUG, " selected based on WPS IE");
1772 } else {
1773 wpa_printf(MSG_DEBUG, " selected based on WPS IE "
1774 "(Authorized MAC or Active PIN)");
1775 }
1776 wpabuf_free(wps_ie);
1777 return 1;
1778 }
1779
1780 if (wps_ie) {
1781 wpa_printf(MSG_DEBUG, " selected based on WPS IE");
1782 wpabuf_free(wps_ie);
1783 return 1;
1784 }
1785
1786 return -1;
1787}
1788
1789
1790int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
1791 struct wpa_ssid *ssid,
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -07001792 struct wpa_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001793{
1794 struct wpabuf *wps_ie = NULL;
1795 int ret = 0;
1796
1797 if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001798 wps_ie = wpas_wps_get_wps_ie(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001799 if (wps_ie && wps_is_selected_pbc_registrar(wps_ie)) {
1800 /* allow wildcard SSID for WPS PBC */
1801 ret = 1;
1802 }
1803 } else if (eap_is_wps_pin_enrollee(&ssid->eap)) {
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001804 wps_ie = wpas_wps_get_wps_ie(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001805 if (wps_ie &&
1806 (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1) ||
1807 wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) {
1808 /* allow wildcard SSID for WPS PIN */
1809 ret = 1;
1810 }
1811 }
1812
1813 if (!ret && ssid->bssid_set &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001814 ether_addr_equal(ssid->bssid, bss->bssid)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001815 /* allow wildcard SSID due to hardcoded BSSID match */
1816 ret = 1;
1817 }
1818
1819#ifdef CONFIG_WPS_STRICT
1820 if (wps_ie) {
1821 if (wps_validate_beacon_probe_resp(wps_ie, bss->beacon_ie_len >
1822 0, bss->bssid) < 0)
1823 ret = 0;
1824 if (bss->beacon_ie_len) {
1825 struct wpabuf *bcn_wps;
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -07001826 bcn_wps = wpa_bss_get_vendor_ie_multi_beacon(
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001827 bss, WPS_IE_VENDOR_TYPE);
1828 if (bcn_wps == NULL) {
1829 wpa_printf(MSG_DEBUG, "WPS: Mandatory WPS IE "
1830 "missing from AP Beacon");
1831 ret = 0;
1832 } else {
1833 if (wps_validate_beacon(wps_ie) < 0)
1834 ret = 0;
1835 wpabuf_free(bcn_wps);
1836 }
1837 }
1838 }
1839#endif /* CONFIG_WPS_STRICT */
1840
1841 wpabuf_free(wps_ie);
1842
1843 return ret;
1844}
1845
1846
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001847static bool wpas_wps_is_pbc_overlap(struct wps_ap_info *ap,
1848 struct wpa_bss *selected,
1849 struct wpa_ssid *ssid,
1850 const u8 *sel_uuid)
1851{
1852 if (!ap->pbc_active ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001853 ether_addr_equal(selected->bssid, ap->bssid))
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001854 return false;
1855
1856 if (!is_zero_ether_addr(ssid->bssid) &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001857 !ether_addr_equal(ap->bssid, ssid->bssid)) {
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001858 wpa_printf(MSG_DEBUG, "WPS: Ignore another BSS " MACSTR
1859 " in active PBC mode due to local BSSID limitation",
1860 MAC2STR(ap->bssid));
1861 return 0;
1862 }
1863
1864 wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: " MACSTR,
1865 MAC2STR(ap->bssid));
1866 wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
1867 ap->uuid, UUID_LEN);
1868 if (!sel_uuid || os_memcmp(sel_uuid, ap->uuid, UUID_LEN) != 0)
1869 return true;
1870
1871 /* TODO: verify that this is reasonable dual-band situation */
1872
1873 return false;
1874}
1875
1876
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001877int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
1878 struct wpa_bss *selected, struct wpa_ssid *ssid)
1879{
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001880 struct wpa_supplicant *iface;
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07001881 const u8 *sel_uuid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001882 struct wpabuf *wps_ie;
1883 int ret = 0;
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07001884 size_t i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001885
1886 if (!eap_is_wps_pbc_enrollee(&ssid->eap))
1887 return 0;
1888
1889 wpa_printf(MSG_DEBUG, "WPS: Check whether PBC session overlap is "
1890 "present in scan results; selected BSSID " MACSTR,
1891 MAC2STR(selected->bssid));
Hai Shalomfdcde762020-04-02 11:19:20 -07001892 if (!is_zero_ether_addr(ssid->bssid))
1893 wpa_printf(MSG_DEBUG,
1894 "WPS: Network profile limited to accept only a single BSSID " MACSTR,
1895 MAC2STR(ssid->bssid));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001896
1897 /* Make sure that only one AP is in active PBC mode */
1898 wps_ie = wpa_bss_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE);
1899 if (wps_ie) {
1900 sel_uuid = wps_get_uuid_e(wps_ie);
1901 wpa_hexdump(MSG_DEBUG, "WPS: UUID of the selected BSS",
1902 sel_uuid, UUID_LEN);
1903 } else {
1904 wpa_printf(MSG_DEBUG, "WPS: Selected BSS does not include "
1905 "WPS IE?!");
1906 sel_uuid = NULL;
1907 }
1908
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001909 for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
1910 for (i = 0; i < iface->num_wps_ap; i++) {
1911 struct wps_ap_info *ap = &iface->wps_ap[i];
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07001912
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001913 if (wpas_wps_is_pbc_overlap(ap, selected, ssid,
1914 sel_uuid)) {
1915 ret = 1; /* PBC overlap */
1916 wpa_msg(iface, MSG_INFO,
1917 "WPS: PBC overlap detected: "
1918 MACSTR " and " MACSTR,
1919 MAC2STR(selected->bssid),
1920 MAC2STR(ap->bssid));
1921 break;
1922 }
Hai Shalomfdcde762020-04-02 11:19:20 -07001923 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001924 }
1925
1926 wpabuf_free(wps_ie);
1927
1928 return ret;
1929}
1930
1931
1932void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s)
1933{
1934 struct wpa_bss *bss;
1935 unsigned int pbc = 0, auth = 0, pin = 0, wps = 0;
1936
1937 if (wpa_s->disconnected || wpa_s->wpa_state >= WPA_ASSOCIATED)
1938 return;
1939
1940 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
1941 struct wpabuf *ie;
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001942
1943 ie = wpas_wps_get_wps_ie(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001944 if (!ie)
1945 continue;
1946 if (wps_is_selected_pbc_registrar(ie))
1947 pbc++;
1948 else if (wps_is_addr_authorized(ie, wpa_s->own_addr, 0))
1949 auth++;
1950 else if (wps_is_selected_pin_registrar(ie))
1951 pin++;
1952 else
1953 wps++;
1954 wpabuf_free(ie);
1955 }
1956
1957 if (pbc)
1958 wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PBC);
1959 else if (auth)
1960 wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_AUTH);
1961 else if (pin)
1962 wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PIN);
1963 else if (wps)
1964 wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE);
1965}
1966
1967
1968int wpas_wps_searching(struct wpa_supplicant *wpa_s)
1969{
1970 struct wpa_ssid *ssid;
1971
1972 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1973 if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && !ssid->disabled)
1974 return 1;
1975 }
1976
1977 return 0;
1978}
1979
1980
1981int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
1982 char *end)
1983{
1984 struct wpabuf *wps_ie;
1985 int ret;
1986
1987 wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, WPS_DEV_OUI_WFA);
1988 if (wps_ie == NULL)
1989 return 0;
1990
1991 ret = wps_attr_text(wps_ie, buf, end);
1992 wpabuf_free(wps_ie);
1993 return ret;
1994}
1995
1996
1997int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter)
1998{
1999#ifdef CONFIG_WPS_ER
2000 if (wpa_s->wps_er) {
2001 wps_er_refresh(wpa_s->wps_er);
2002 return 0;
2003 }
2004 wpa_s->wps_er = wps_er_init(wpa_s->wps, wpa_s->ifname, filter);
2005 if (wpa_s->wps_er == NULL)
2006 return -1;
2007 return 0;
2008#else /* CONFIG_WPS_ER */
2009 return 0;
2010#endif /* CONFIG_WPS_ER */
2011}
2012
2013
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002014void wpas_wps_er_stop(struct wpa_supplicant *wpa_s)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002015{
2016#ifdef CONFIG_WPS_ER
2017 wps_er_deinit(wpa_s->wps_er, NULL, NULL);
2018 wpa_s->wps_er = NULL;
2019#endif /* CONFIG_WPS_ER */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002020}
2021
2022
2023#ifdef CONFIG_WPS_ER
2024int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr,
2025 const char *uuid, const char *pin)
2026{
2027 u8 u[UUID_LEN];
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002028 const u8 *use_uuid = NULL;
2029 u8 addr_buf[ETH_ALEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002030
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002031 if (os_strcmp(uuid, "any") == 0) {
2032 } else if (uuid_str2bin(uuid, u) == 0) {
2033 use_uuid = u;
2034 } else if (hwaddr_aton(uuid, addr_buf) == 0) {
2035 use_uuid = wps_er_get_sta_uuid(wpa_s->wps_er, addr_buf);
2036 if (use_uuid == NULL)
2037 return -1;
2038 } else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002039 return -1;
2040 return wps_registrar_add_pin(wpa_s->wps->registrar, addr,
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002041 use_uuid,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002042 (const u8 *) pin, os_strlen(pin), 300);
2043}
2044
2045
2046int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid)
2047{
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002048 u8 u[UUID_LEN], *use_uuid = NULL;
2049 u8 addr[ETH_ALEN], *use_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002050
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002051 if (uuid_str2bin(uuid, u) == 0)
2052 use_uuid = u;
2053 else if (hwaddr_aton(uuid, addr) == 0)
2054 use_addr = addr;
2055 else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002056 return -1;
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002057 return wps_er_pbc(wpa_s->wps_er, use_uuid, use_addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002058}
2059
2060
2061int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
2062 const char *pin)
2063{
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002064 u8 u[UUID_LEN], *use_uuid = NULL;
2065 u8 addr[ETH_ALEN], *use_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002066
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002067 if (uuid_str2bin(uuid, u) == 0)
2068 use_uuid = u;
2069 else if (hwaddr_aton(uuid, addr) == 0)
2070 use_addr = addr;
2071 else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002072 return -1;
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002073
2074 return wps_er_learn(wpa_s->wps_er, use_uuid, use_addr, (const u8 *) pin,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002075 os_strlen(pin));
2076}
2077
2078
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002079static int wpas_wps_network_to_cred(struct wpa_ssid *ssid,
2080 struct wps_credential *cred)
2081{
2082 os_memset(cred, 0, sizeof(*cred));
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07002083 if (ssid->ssid_len > SSID_MAX_LEN)
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002084 return -1;
2085 os_memcpy(cred->ssid, ssid->ssid, ssid->ssid_len);
2086 cred->ssid_len = ssid->ssid_len;
2087 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
2088 cred->auth_type = (ssid->proto & WPA_PROTO_RSN) ?
2089 WPS_AUTH_WPA2PSK : WPS_AUTH_WPAPSK;
2090 if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
2091 cred->encr_type = WPS_ENCR_AES;
2092 else
2093 cred->encr_type = WPS_ENCR_TKIP;
2094 if (ssid->passphrase) {
2095 cred->key_len = os_strlen(ssid->passphrase);
2096 if (cred->key_len >= 64)
2097 return -1;
2098 os_memcpy(cred->key, ssid->passphrase, cred->key_len);
2099 } else if (ssid->psk_set) {
2100 cred->key_len = 32;
2101 os_memcpy(cred->key, ssid->psk, 32);
2102 } else
2103 return -1;
2104 } else {
2105 cred->auth_type = WPS_AUTH_OPEN;
2106 cred->encr_type = WPS_ENCR_NONE;
2107 }
2108
2109 return 0;
2110}
2111
2112
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002113int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
2114 int id)
2115{
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002116 u8 u[UUID_LEN], *use_uuid = NULL;
2117 u8 addr[ETH_ALEN], *use_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002118 struct wpa_ssid *ssid;
2119 struct wps_credential cred;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002120 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002121
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002122 if (uuid_str2bin(uuid, u) == 0)
2123 use_uuid = u;
2124 else if (hwaddr_aton(uuid, addr) == 0)
2125 use_addr = addr;
2126 else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002127 return -1;
2128 ssid = wpa_config_get_network(wpa_s->conf, id);
2129 if (ssid == NULL || ssid->ssid == NULL)
2130 return -1;
2131
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002132 if (wpas_wps_network_to_cred(ssid, &cred) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002133 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002134 ret = wps_er_set_config(wpa_s->wps_er, use_uuid, use_addr, &cred);
2135 os_memset(&cred, 0, sizeof(cred));
2136 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002137}
2138
2139
2140int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
2141 const char *pin, struct wps_new_ap_settings *settings)
2142{
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002143 u8 u[UUID_LEN], *use_uuid = NULL;
2144 u8 addr[ETH_ALEN], *use_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002145 struct wps_credential cred;
2146 size_t len;
2147
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002148 if (uuid_str2bin(uuid, u) == 0)
2149 use_uuid = u;
2150 else if (hwaddr_aton(uuid, addr) == 0)
2151 use_addr = addr;
2152 else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002153 return -1;
2154 if (settings->ssid_hex == NULL || settings->auth == NULL ||
2155 settings->encr == NULL || settings->key_hex == NULL)
2156 return -1;
2157
2158 os_memset(&cred, 0, sizeof(cred));
2159 len = os_strlen(settings->ssid_hex);
2160 if ((len & 1) || len > 2 * sizeof(cred.ssid) ||
2161 hexstr2bin(settings->ssid_hex, cred.ssid, len / 2))
2162 return -1;
2163 cred.ssid_len = len / 2;
2164
2165 len = os_strlen(settings->key_hex);
2166 if ((len & 1) || len > 2 * sizeof(cred.key) ||
2167 hexstr2bin(settings->key_hex, cred.key, len / 2))
2168 return -1;
2169 cred.key_len = len / 2;
2170
2171 if (os_strcmp(settings->auth, "OPEN") == 0)
2172 cred.auth_type = WPS_AUTH_OPEN;
2173 else if (os_strcmp(settings->auth, "WPAPSK") == 0)
2174 cred.auth_type = WPS_AUTH_WPAPSK;
2175 else if (os_strcmp(settings->auth, "WPA2PSK") == 0)
2176 cred.auth_type = WPS_AUTH_WPA2PSK;
2177 else
2178 return -1;
2179
2180 if (os_strcmp(settings->encr, "NONE") == 0)
2181 cred.encr_type = WPS_ENCR_NONE;
Dmitry Shmidt21de2142014-04-08 10:50:52 -07002182#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002183 else if (os_strcmp(settings->encr, "WEP") == 0)
2184 cred.encr_type = WPS_ENCR_WEP;
Dmitry Shmidt21de2142014-04-08 10:50:52 -07002185#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002186 else if (os_strcmp(settings->encr, "TKIP") == 0)
2187 cred.encr_type = WPS_ENCR_TKIP;
2188 else if (os_strcmp(settings->encr, "CCMP") == 0)
2189 cred.encr_type = WPS_ENCR_AES;
2190 else
2191 return -1;
2192
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002193 return wps_er_config(wpa_s->wps_er, use_uuid, use_addr,
2194 (const u8 *) pin, os_strlen(pin), &cred);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002195}
2196
2197
Dmitry Shmidt04949592012-07-19 12:16:46 -07002198#ifdef CONFIG_WPS_NFC
2199struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
2200 int ndef, const char *uuid)
2201{
2202 struct wpabuf *ret;
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002203 u8 u[UUID_LEN], *use_uuid = NULL;
2204 u8 addr[ETH_ALEN], *use_addr = NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002205
2206 if (!wpa_s->wps_er)
2207 return NULL;
2208
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002209 if (uuid_str2bin(uuid, u) == 0)
2210 use_uuid = u;
2211 else if (hwaddr_aton(uuid, addr) == 0)
2212 use_addr = addr;
2213 else
Dmitry Shmidt04949592012-07-19 12:16:46 -07002214 return NULL;
2215
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002216 ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002217 if (ndef && ret) {
2218 struct wpabuf *tmp;
2219 tmp = ndef_build_wifi(ret);
2220 wpabuf_free(ret);
2221 if (tmp == NULL)
2222 return NULL;
2223 ret = tmp;
2224 }
2225
2226 return ret;
2227}
2228#endif /* CONFIG_WPS_NFC */
2229
2230
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002231static int callbacks_pending = 0;
2232
2233static void wpas_wps_terminate_cb(void *ctx)
2234{
2235 wpa_printf(MSG_DEBUG, "WPS ER: Terminated");
2236 if (--callbacks_pending <= 0)
2237 eloop_terminate();
2238}
2239#endif /* CONFIG_WPS_ER */
2240
2241
2242int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s)
2243{
2244#ifdef CONFIG_WPS_ER
2245 if (wpa_s->wps_er) {
2246 callbacks_pending++;
2247 wps_er_deinit(wpa_s->wps_er, wpas_wps_terminate_cb, wpa_s);
2248 wpa_s->wps_er = NULL;
2249 return 1;
2250 }
2251#endif /* CONFIG_WPS_ER */
2252 return 0;
2253}
2254
2255
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002256void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
2257{
2258 struct wps_context *wps = wpa_s->wps;
2259
2260 if (wps == NULL)
2261 return;
2262
2263 if (wpa_s->conf->changed_parameters & CFG_CHANGED_CONFIG_METHODS) {
2264 wps->config_methods = wps_config_methods_str2bin(
2265 wpa_s->conf->config_methods);
2266 if ((wps->config_methods &
2267 (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) ==
2268 (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) {
2269 wpa_printf(MSG_ERROR, "WPS: Both Label and Display "
2270 "config methods are not allowed at the "
2271 "same time");
2272 wps->config_methods &= ~WPS_CONFIG_LABEL;
2273 }
2274 }
2275 wps->config_methods = wps_fix_config_methods(wps->config_methods);
jim1_linff2bda62012-06-26 11:04:38 +08002276 wps->dev.config_methods = wps->config_methods;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002277
2278 if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE)
2279 os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type,
2280 WPS_DEV_TYPE_LEN);
2281
2282 if (wpa_s->conf->changed_parameters & CFG_CHANGED_SEC_DEVICE_TYPE) {
2283 wps->dev.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
2284 os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type,
2285 wps->dev.num_sec_dev_types * WPS_DEV_TYPE_LEN);
2286 }
2287
Dmitry Shmidt04949592012-07-19 12:16:46 -07002288 if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION)
2289 wpas_wps_set_vendor_ext_m1(wpa_s, wps);
2290
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002291 if (wpa_s->conf->changed_parameters & CFG_CHANGED_OS_VERSION)
2292 wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
2293
2294 if (wpa_s->conf->changed_parameters & CFG_CHANGED_UUID)
2295 wpas_wps_set_uuid(wpa_s, wps);
2296
2297 if (wpa_s->conf->changed_parameters &
2298 (CFG_CHANGED_DEVICE_NAME | CFG_CHANGED_WPS_STRING)) {
2299 /* Update pointers to make sure they refer current values */
2300 wps->dev.device_name = wpa_s->conf->device_name;
2301 wps->dev.manufacturer = wpa_s->conf->manufacturer;
2302 wps->dev.model_name = wpa_s->conf->model_name;
2303 wps->dev.model_number = wpa_s->conf->model_number;
2304 wps->dev.serial_number = wpa_s->conf->serial_number;
2305 }
2306}
Dmitry Shmidt04949592012-07-19 12:16:46 -07002307
2308
Mikael Kanstrupcc779b82019-08-16 08:50:54 +02002309void wpas_wps_update_mac_addr(struct wpa_supplicant *wpa_s)
2310{
2311 struct wps_context *wps;
2312
2313 wps = wpa_s->wps;
2314 if (wps)
2315 os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
2316}
2317
2318
Dmitry Shmidt04949592012-07-19 12:16:46 -07002319#ifdef CONFIG_WPS_NFC
2320
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002321#ifdef CONFIG_WPS_ER
Roshan Pius8894db22017-02-13 14:43:20 -08002322struct wpabuf *
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002323wpas_wps_network_config_token(struct wpa_supplicant *wpa_s, int ndef,
2324 struct wpa_ssid *ssid)
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002325{
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002326 struct wpabuf *ret;
2327 struct wps_credential cred;
2328
2329 if (wpas_wps_network_to_cred(ssid, &cred) < 0)
2330 return NULL;
2331
2332 ret = wps_er_config_token_from_cred(wpa_s->wps, &cred);
2333
2334 if (ndef && ret) {
2335 struct wpabuf *tmp;
2336 tmp = ndef_build_wifi(ret);
2337 wpabuf_free(ret);
2338 if (tmp == NULL)
2339 return NULL;
2340 ret = tmp;
2341 }
2342
2343 return ret;
2344}
2345#endif /* CONFIG_WPS_ER */
2346
2347
2348struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
2349 int ndef, const char *id_str)
2350{
2351#ifdef CONFIG_WPS_ER
2352 if (id_str) {
2353 int id;
2354 char *end = NULL;
2355 struct wpa_ssid *ssid;
2356
2357 id = strtol(id_str, &end, 10);
2358 if (end && *end)
2359 return NULL;
2360
2361 ssid = wpa_config_get_network(wpa_s->conf, id);
2362 if (ssid == NULL)
2363 return NULL;
2364 return wpas_wps_network_config_token(wpa_s, ndef, ssid);
2365 }
2366#endif /* CONFIG_WPS_ER */
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002367#ifdef CONFIG_AP
2368 if (wpa_s->ap_iface)
2369 return wpas_ap_wps_nfc_config_token(wpa_s, ndef);
2370#endif /* CONFIG_AP */
2371 return NULL;
2372}
2373
2374
Dmitry Shmidt04949592012-07-19 12:16:46 -07002375struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef)
2376{
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002377 if (wpa_s->conf->wps_nfc_pw_from_config) {
2378 return wps_nfc_token_build(ndef,
2379 wpa_s->conf->wps_nfc_dev_pw_id,
2380 wpa_s->conf->wps_nfc_dh_pubkey,
2381 wpa_s->conf->wps_nfc_dev_pw);
2382 }
2383
Dmitry Shmidt04949592012-07-19 12:16:46 -07002384 return wps_nfc_token_gen(ndef, &wpa_s->conf->wps_nfc_dev_pw_id,
2385 &wpa_s->conf->wps_nfc_dh_pubkey,
2386 &wpa_s->conf->wps_nfc_dh_privkey,
2387 &wpa_s->conf->wps_nfc_dev_pw);
2388}
2389
2390
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002391int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *go_dev_addr,
2392 const u8 *bssid,
2393 const struct wpabuf *dev_pw, u16 dev_pw_id,
2394 int p2p_group, const u8 *peer_pubkey_hash,
2395 const u8 *ssid, size_t ssid_len, int freq)
Dmitry Shmidt04949592012-07-19 12:16:46 -07002396{
2397 struct wps_context *wps = wpa_s->wps;
2398 char pw[32 * 2 + 1];
2399
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002400 if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && dev_pw == NULL) {
2401 dev_pw = wpa_s->conf->wps_nfc_dev_pw;
2402 dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id;
2403 }
2404
Dmitry Shmidt04949592012-07-19 12:16:46 -07002405 if (wpa_s->conf->wps_nfc_dh_pubkey == NULL ||
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002406 wpa_s->conf->wps_nfc_dh_privkey == NULL) {
2407 wpa_printf(MSG_DEBUG, "WPS: Missing DH params - "
2408 "cannot start NFC-triggered connection");
Dmitry Shmidt04949592012-07-19 12:16:46 -07002409 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002410 }
2411
2412 if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && dev_pw == NULL) {
2413 wpa_printf(MSG_DEBUG, "WPS: Missing Device Password (id=%u) - "
2414 "cannot start NFC-triggered connection", dev_pw_id);
2415 return -1;
2416 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002417
2418 dh5_free(wps->dh_ctx);
2419 wpabuf_free(wps->dh_pubkey);
2420 wpabuf_free(wps->dh_privkey);
2421 wps->dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
2422 wps->dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
2423 if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
2424 wps->dh_ctx = NULL;
2425 wpabuf_free(wps->dh_pubkey);
2426 wps->dh_pubkey = NULL;
2427 wpabuf_free(wps->dh_privkey);
2428 wps->dh_privkey = NULL;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002429 wpa_printf(MSG_DEBUG, "WPS: Failed to get DH priv/pub key");
Dmitry Shmidt04949592012-07-19 12:16:46 -07002430 return -1;
2431 }
2432 wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002433 if (wps->dh_ctx == NULL) {
2434 wpabuf_free(wps->dh_pubkey);
2435 wps->dh_pubkey = NULL;
2436 wpabuf_free(wps->dh_privkey);
2437 wps->dh_privkey = NULL;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002438 wpa_printf(MSG_DEBUG, "WPS: Failed to initialize DH context");
Dmitry Shmidt04949592012-07-19 12:16:46 -07002439 return -1;
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002440 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002441
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002442 if (dev_pw) {
2443 wpa_snprintf_hex_uppercase(pw, sizeof(pw),
2444 wpabuf_head(dev_pw),
2445 wpabuf_len(dev_pw));
2446 }
2447 return wpas_wps_start_dev_pw(wpa_s, go_dev_addr, bssid,
2448 dev_pw ? pw : NULL,
2449 p2p_group, dev_pw_id, peer_pubkey_hash,
2450 ssid, ssid_len, freq);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002451}
2452
2453
2454static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
2455 struct wps_parse_attr *attr)
2456{
Dmitry Shmidt44c95782013-05-17 09:51:35 -07002457 /*
2458 * Disable existing networks temporarily to allow the newly learned
2459 * credential to be preferred. Enable the temporarily disabled networks
2460 * after 10 seconds.
2461 */
2462 wpas_wps_temp_disable(wpa_s, NULL);
2463 eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
2464 NULL);
2465
Dmitry Shmidt04949592012-07-19 12:16:46 -07002466 if (wps_oob_use_cred(wpa_s->wps, attr) < 0)
2467 return -1;
2468
2469 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
2470 return 0;
2471
Dmitry Shmidt3c479372014-02-04 10:50:36 -08002472 if (attr->ap_channel) {
2473 u16 chan = WPA_GET_BE16(attr->ap_channel);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002474 int freq = 0;
2475
2476 if (chan >= 1 && chan <= 13)
2477 freq = 2407 + 5 * chan;
2478 else if (chan == 14)
2479 freq = 2484;
2480 else if (chan >= 30)
2481 freq = 5000 + 5 * chan;
2482
2483 if (freq) {
Dmitry Shmidt3c479372014-02-04 10:50:36 -08002484 wpa_printf(MSG_DEBUG, "WPS: Credential container indicated AP channel %u -> %u MHz",
2485 chan, freq);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002486 wpa_s->after_wps = 5;
2487 wpa_s->wps_freq = freq;
2488 }
2489 }
Dmitry Shmidt3c479372014-02-04 10:50:36 -08002490
2491 wpa_printf(MSG_DEBUG, "WPS: Request reconnection with new network "
2492 "based on the received credential added");
2493 wpa_s->normal_scans = 0;
2494 wpa_supplicant_reinit_autoscan(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002495 wpa_s->disconnected = 0;
2496 wpa_s->reassociate = 1;
Dmitry Shmidt96571392013-10-14 12:54:46 -07002497
2498 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002499 wpa_supplicant_req_scan(wpa_s, 0, 0);
2500
2501 return 0;
2502}
2503
2504
Dmitry Shmidtaa532512012-09-24 10:35:31 -07002505#ifdef CONFIG_WPS_ER
Dmitry Shmidt04949592012-07-19 12:16:46 -07002506static int wpas_wps_add_nfc_password_token(struct wpa_supplicant *wpa_s,
2507 struct wps_parse_attr *attr)
2508{
2509 return wps_registrar_add_nfc_password_token(
2510 wpa_s->wps->registrar, attr->oob_dev_password,
2511 attr->oob_dev_password_len);
2512}
Dmitry Shmidtaa532512012-09-24 10:35:31 -07002513#endif /* CONFIG_WPS_ER */
Dmitry Shmidt04949592012-07-19 12:16:46 -07002514
2515
2516static int wpas_wps_nfc_tag_process(struct wpa_supplicant *wpa_s,
2517 const struct wpabuf *wps)
2518{
2519 struct wps_parse_attr attr;
2520
2521 wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
2522
2523 if (wps_parse_msg(wps, &attr)) {
2524 wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
2525 return -1;
2526 }
2527
2528 if (attr.num_cred)
2529 return wpas_wps_use_cred(wpa_s, &attr);
2530
2531#ifdef CONFIG_WPS_ER
2532 if (attr.oob_dev_password)
2533 return wpas_wps_add_nfc_password_token(wpa_s, &attr);
2534#endif /* CONFIG_WPS_ER */
2535
2536 wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
2537 return -1;
2538}
2539
2540
2541int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002542 const struct wpabuf *data, int forced_freq)
Dmitry Shmidt04949592012-07-19 12:16:46 -07002543{
2544 const struct wpabuf *wps = data;
2545 struct wpabuf *tmp = NULL;
2546 int ret;
2547
2548 if (wpabuf_len(data) < 4)
2549 return -1;
2550
2551 if (*wpabuf_head_u8(data) != 0x10) {
2552 /* Assume this contains full NDEF record */
2553 tmp = ndef_parse_wifi(data);
2554 if (tmp == NULL) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002555#ifdef CONFIG_P2P
2556 tmp = ndef_parse_p2p(data);
2557 if (tmp) {
2558 ret = wpas_p2p_nfc_tag_process(wpa_s, tmp,
2559 forced_freq);
2560 wpabuf_free(tmp);
2561 return ret;
2562 }
2563#endif /* CONFIG_P2P */
Dmitry Shmidt04949592012-07-19 12:16:46 -07002564 wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
2565 return -1;
2566 }
2567 wps = tmp;
2568 }
2569
2570 ret = wpas_wps_nfc_tag_process(wpa_s, wps);
2571 wpabuf_free(tmp);
2572 return ret;
2573}
2574
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002575
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002576struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s,
2577 int ndef)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002578{
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002579 struct wpabuf *ret;
2580
2581 if (wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
2582 wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
2583 &wpa_s->conf->wps_nfc_dh_privkey) < 0)
2584 return NULL;
2585
2586 ret = wps_build_nfc_handover_req(wpa_s->wps,
2587 wpa_s->conf->wps_nfc_dh_pubkey);
2588
2589 if (ndef && ret) {
2590 struct wpabuf *tmp;
2591 tmp = ndef_build_wifi(ret);
2592 wpabuf_free(ret);
2593 if (tmp == NULL)
2594 return NULL;
2595 ret = tmp;
2596 }
2597
2598 return ret;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002599}
2600
2601
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002602#ifdef CONFIG_WPS_NFC
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002603
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002604static struct wpabuf *
2605wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef,
2606 const char *uuid)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002607{
Dmitry Shmidt700a1372013-03-15 14:14:44 -07002608#ifdef CONFIG_WPS_ER
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002609 struct wpabuf *ret;
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002610 u8 u[UUID_LEN], *use_uuid = NULL;
2611 u8 addr[ETH_ALEN], *use_addr = NULL;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002612 struct wps_context *wps = wpa_s->wps;
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002613
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002614 if (wps == NULL)
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002615 return NULL;
2616
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002617 if (uuid == NULL)
2618 return NULL;
2619 if (uuid_str2bin(uuid, u) == 0)
2620 use_uuid = u;
2621 else if (hwaddr_aton(uuid, addr) == 0)
2622 use_addr = addr;
2623 else
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002624 return NULL;
2625
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002626 if (wpa_s->conf->wps_nfc_dh_pubkey == NULL) {
2627 if (wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
2628 &wpa_s->conf->wps_nfc_dh_privkey) < 0)
2629 return NULL;
2630 }
2631
2632 wpas_wps_nfc_clear(wps);
2633 wps->ap_nfc_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
2634 wps->ap_nfc_dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
2635 wps->ap_nfc_dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
2636 if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey) {
2637 wpas_wps_nfc_clear(wps);
2638 return NULL;
2639 }
2640
2641 ret = wps_er_nfc_handover_sel(wpa_s->wps_er, wpa_s->wps, use_uuid,
2642 use_addr, wpa_s->conf->wps_nfc_dh_pubkey);
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002643 if (ndef && ret) {
2644 struct wpabuf *tmp;
2645 tmp = ndef_build_wifi(ret);
2646 wpabuf_free(ret);
2647 if (tmp == NULL)
2648 return NULL;
2649 ret = tmp;
2650 }
2651
2652 return ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07002653#else /* CONFIG_WPS_ER */
2654 return NULL;
2655#endif /* CONFIG_WPS_ER */
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002656}
2657#endif /* CONFIG_WPS_NFC */
2658
2659
2660struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
2661 int ndef, int cr, const char *uuid)
2662{
2663 struct wpabuf *ret;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002664 if (!cr)
2665 return NULL;
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002666 ret = wpas_ap_wps_nfc_handover_sel(wpa_s, ndef);
2667 if (ret)
2668 return ret;
2669 return wpas_wps_er_nfc_handover_sel(wpa_s, ndef, uuid);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002670}
2671
2672
Dmitry Shmidt21de2142014-04-08 10:50:52 -07002673static int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
2674 const struct wpabuf *data)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002675{
2676 struct wpabuf *wps;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002677 int ret = -1;
2678 u16 wsc_len;
2679 const u8 *pos;
2680 struct wpabuf msg;
2681 struct wps_parse_attr attr;
2682 u16 dev_pw_id;
2683 const u8 *bssid = NULL;
2684 int freq = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002685
2686 wps = ndef_parse_wifi(data);
2687 if (wps == NULL)
2688 return -1;
2689 wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
2690 "payload from NFC connection handover");
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002691 wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
2692 if (wpabuf_len(wps) < 2) {
2693 wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Select "
2694 "Message");
2695 goto out;
2696 }
2697 pos = wpabuf_head(wps);
2698 wsc_len = WPA_GET_BE16(pos);
2699 if (wsc_len > wpabuf_len(wps) - 2) {
2700 wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
2701 "in Wi-Fi Handover Select Message", wsc_len);
2702 goto out;
2703 }
2704 pos += 2;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002705
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002706 wpa_hexdump(MSG_DEBUG,
2707 "WPS: WSC attributes in Wi-Fi Handover Select Message",
2708 pos, wsc_len);
2709 if (wsc_len < wpabuf_len(wps) - 2) {
2710 wpa_hexdump(MSG_DEBUG,
2711 "WPS: Ignore extra data after WSC attributes",
2712 pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
2713 }
2714
2715 wpabuf_set(&msg, pos, wsc_len);
2716 ret = wps_parse_msg(&msg, &attr);
2717 if (ret < 0) {
2718 wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
2719 "Wi-Fi Handover Select Message");
2720 goto out;
2721 }
2722
2723 if (attr.oob_dev_password == NULL ||
2724 attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
2725 wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
2726 "included in Wi-Fi Handover Select Message");
2727 ret = -1;
2728 goto out;
2729 }
2730
2731 if (attr.ssid == NULL) {
2732 wpa_printf(MSG_DEBUG, "WPS: No SSID included in Wi-Fi Handover "
2733 "Select Message");
2734 ret = -1;
2735 goto out;
2736 }
2737
2738 wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", attr.ssid, attr.ssid_len);
2739
2740 if (attr.mac_addr) {
2741 bssid = attr.mac_addr;
2742 wpa_printf(MSG_DEBUG, "WPS: MAC Address (BSSID): " MACSTR,
2743 MAC2STR(bssid));
2744 }
2745
2746 if (attr.rf_bands)
2747 wpa_printf(MSG_DEBUG, "WPS: RF Bands: %d", *attr.rf_bands);
2748
2749 if (attr.ap_channel) {
2750 u16 chan = WPA_GET_BE16(attr.ap_channel);
2751
2752 wpa_printf(MSG_DEBUG, "WPS: AP Channel: %d", chan);
2753
2754 if (chan >= 1 && chan <= 13 &&
2755 (attr.rf_bands == NULL || *attr.rf_bands & WPS_RF_24GHZ))
2756 freq = 2407 + 5 * chan;
2757 else if (chan == 14 &&
2758 (attr.rf_bands == NULL ||
2759 *attr.rf_bands & WPS_RF_24GHZ))
2760 freq = 2484;
2761 else if (chan >= 30 &&
2762 (attr.rf_bands == NULL ||
2763 *attr.rf_bands & WPS_RF_50GHZ))
2764 freq = 5000 + 5 * chan;
Hai Shalomc3565922019-10-28 11:58:20 -07002765 else if (chan >= 1 && chan <= 6 &&
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07002766 (attr.rf_bands == NULL ||
2767 *attr.rf_bands & WPS_RF_60GHZ))
2768 freq = 56160 + 2160 * chan;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002769
2770 if (freq) {
2771 wpa_printf(MSG_DEBUG,
2772 "WPS: AP indicated channel %u -> %u MHz",
2773 chan, freq);
2774 }
2775 }
2776
2777 wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
2778 attr.oob_dev_password, attr.oob_dev_password_len);
2779 dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
2780 WPS_OOB_PUBKEY_HASH_LEN);
2781 if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
2782 wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
2783 "%u in Wi-Fi Handover Select Message", dev_pw_id);
2784 ret = -1;
2785 goto out;
2786 }
2787 wpa_hexdump(MSG_DEBUG, "WPS: AP Public Key hash",
2788 attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
2789
2790 ret = wpas_wps_start_nfc(wpa_s, NULL, bssid, NULL, dev_pw_id, 0,
2791 attr.oob_dev_password,
2792 attr.ssid, attr.ssid_len, freq);
2793
2794out:
2795 wpabuf_free(wps);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002796 return ret;
2797}
2798
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002799
2800int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
2801 const struct wpabuf *req,
2802 const struct wpabuf *sel)
2803{
2804 wpa_printf(MSG_DEBUG, "NFC: WPS connection handover reported");
2805 wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in request", req);
2806 wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in select", sel);
2807 return wpas_wps_nfc_rx_handover_sel(wpa_s, sel);
2808}
2809
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002810
2811int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
2812 const struct wpabuf *req,
2813 const struct wpabuf *sel)
2814{
2815 struct wpabuf *wps;
2816 int ret = -1;
2817 u16 wsc_len;
2818 const u8 *pos;
2819 struct wpabuf msg;
2820 struct wps_parse_attr attr;
2821 u16 dev_pw_id;
2822
2823 /*
2824 * Enrollee/station is always initiator of the NFC connection handover,
2825 * so use the request message here to find Enrollee public key hash.
2826 */
2827 wps = ndef_parse_wifi(req);
2828 if (wps == NULL)
2829 return -1;
2830 wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
2831 "payload from NFC connection handover");
2832 wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
2833 if (wpabuf_len(wps) < 2) {
2834 wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Request "
2835 "Message");
2836 goto out;
2837 }
2838 pos = wpabuf_head(wps);
2839 wsc_len = WPA_GET_BE16(pos);
2840 if (wsc_len > wpabuf_len(wps) - 2) {
2841 wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
2842 "in rt Wi-Fi Handover Request Message", wsc_len);
2843 goto out;
2844 }
2845 pos += 2;
2846
2847 wpa_hexdump(MSG_DEBUG,
2848 "WPS: WSC attributes in Wi-Fi Handover Request Message",
2849 pos, wsc_len);
2850 if (wsc_len < wpabuf_len(wps) - 2) {
2851 wpa_hexdump(MSG_DEBUG,
2852 "WPS: Ignore extra data after WSC attributes",
2853 pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
2854 }
2855
2856 wpabuf_set(&msg, pos, wsc_len);
2857 ret = wps_parse_msg(&msg, &attr);
2858 if (ret < 0) {
2859 wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
2860 "Wi-Fi Handover Request Message");
2861 goto out;
2862 }
2863
2864 if (attr.oob_dev_password == NULL ||
2865 attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
2866 wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
2867 "included in Wi-Fi Handover Request Message");
2868 ret = -1;
2869 goto out;
2870 }
2871
2872 if (attr.uuid_e == NULL) {
2873 wpa_printf(MSG_DEBUG, "WPS: No UUID-E included in Wi-Fi "
2874 "Handover Request Message");
2875 ret = -1;
2876 goto out;
2877 }
2878
2879 wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", attr.uuid_e, WPS_UUID_LEN);
2880
2881 wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
2882 attr.oob_dev_password, attr.oob_dev_password_len);
2883 dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
2884 WPS_OOB_PUBKEY_HASH_LEN);
2885 if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
2886 wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
2887 "%u in Wi-Fi Handover Request Message", dev_pw_id);
2888 ret = -1;
2889 goto out;
2890 }
2891 wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Public Key hash",
2892 attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
2893
2894 ret = wps_registrar_add_nfc_pw_token(wpa_s->wps->registrar,
2895 attr.oob_dev_password,
2896 DEV_PW_NFC_CONNECTION_HANDOVER,
2897 NULL, 0, 1);
2898
2899out:
2900 wpabuf_free(wps);
2901 return ret;
2902}
2903
Dmitry Shmidt04949592012-07-19 12:16:46 -07002904#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002905
2906
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002907static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s)
2908{
2909 size_t i;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002910 struct os_reltime now;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002911
2912 if (wpa_debug_level > MSG_DEBUG)
2913 return;
2914
2915 if (wpa_s->wps_ap == NULL)
2916 return;
2917
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002918 os_get_reltime(&now);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002919
2920 for (i = 0; i < wpa_s->num_wps_ap; i++) {
2921 struct wps_ap_info *ap = &wpa_s->wps_ap[i];
Hai Shalom60840252021-02-19 19:02:11 -08002922 struct wpa_bssid_ignore *e = wpa_bssid_ignore_get(wpa_s,
2923 ap->bssid);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002924
2925 wpa_printf(MSG_DEBUG, "WPS: AP[%d] " MACSTR " type=%d "
Hai Shalom60840252021-02-19 19:02:11 -08002926 "tries=%d last_attempt=%d sec ago bssid_ignore=%d",
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002927 (int) i, MAC2STR(ap->bssid), ap->type, ap->tries,
2928 ap->last_attempt.sec > 0 ?
2929 (int) now.sec - (int) ap->last_attempt.sec : -1,
2930 e ? e->count : 0);
2931 }
2932}
2933
2934
2935static struct wps_ap_info * wpas_wps_get_ap_info(struct wpa_supplicant *wpa_s,
2936 const u8 *bssid)
2937{
2938 size_t i;
2939
2940 if (wpa_s->wps_ap == NULL)
2941 return NULL;
2942
2943 for (i = 0; i < wpa_s->num_wps_ap; i++) {
2944 struct wps_ap_info *ap = &wpa_s->wps_ap[i];
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002945 if (ether_addr_equal(ap->bssid, bssid))
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002946 return ap;
2947 }
2948
2949 return NULL;
2950}
2951
2952
2953static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
2954 struct wpa_scan_res *res)
2955{
2956 struct wpabuf *wps;
2957 enum wps_ap_info_type type;
2958 struct wps_ap_info *ap;
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07002959 int r, pbc_active;
2960 const u8 *uuid;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002961
2962 if (wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE) == NULL)
2963 return;
2964
2965 wps = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
2966 if (wps == NULL)
2967 return;
2968
2969 r = wps_is_addr_authorized(wps, wpa_s->own_addr, 1);
2970 if (r == 2)
2971 type = WPS_AP_SEL_REG_OUR;
2972 else if (r == 1)
2973 type = WPS_AP_SEL_REG;
2974 else
2975 type = WPS_AP_NOT_SEL_REG;
2976
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07002977 uuid = wps_get_uuid_e(wps);
2978 pbc_active = wps_is_selected_pbc_registrar(wps);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002979
2980 ap = wpas_wps_get_ap_info(wpa_s, res->bssid);
2981 if (ap) {
2982 if (ap->type != type) {
2983 wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR
2984 " changed type %d -> %d",
2985 MAC2STR(res->bssid), ap->type, type);
2986 ap->type = type;
2987 if (type != WPS_AP_NOT_SEL_REG)
Hai Shalom60840252021-02-19 19:02:11 -08002988 wpa_bssid_ignore_del(wpa_s, ap->bssid);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002989 }
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07002990 ap->pbc_active = pbc_active;
2991 if (uuid)
2992 os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
2993 goto out;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002994 }
2995
2996 ap = os_realloc_array(wpa_s->wps_ap, wpa_s->num_wps_ap + 1,
2997 sizeof(struct wps_ap_info));
2998 if (ap == NULL)
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07002999 goto out;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003000
3001 wpa_s->wps_ap = ap;
3002 ap = &wpa_s->wps_ap[wpa_s->num_wps_ap];
3003 wpa_s->num_wps_ap++;
3004
3005 os_memset(ap, 0, sizeof(*ap));
3006 os_memcpy(ap->bssid, res->bssid, ETH_ALEN);
3007 ap->type = type;
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07003008 ap->pbc_active = pbc_active;
3009 if (uuid)
3010 os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003011 wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " type %d added",
3012 MAC2STR(ap->bssid), ap->type);
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07003013
3014out:
3015 wpabuf_free(wps);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003016}
3017
3018
3019void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
3020 struct wpa_scan_results *scan_res)
3021{
3022 size_t i;
3023
3024 for (i = 0; i < scan_res->num; i++)
3025 wpas_wps_update_ap_info_bss(wpa_s, scan_res->res[i]);
3026
3027 wpas_wps_dump_ap_info(wpa_s);
3028}
3029
3030
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00003031bool wpas_wps_partner_link_scan_done(struct wpa_supplicant *wpa_s)
3032{
3033 struct wpa_global *global = wpa_s->global;
3034 struct wpa_supplicant *iface;
3035
3036 for (iface = global->ifaces; iface; iface = iface->next) {
3037 if (iface == wpa_s)
3038 continue;
3039
3040 if (!iface->supp_pbc_active)
3041 continue;
3042
3043 /* Scan results are available for both links. While the current
3044 * link will proceed for network selection, ensure the partner
3045 * link also gets an attempt at network selection and connect
3046 * with the selected BSS. */
3047 if (iface->wps_scan_done)
3048 wpa_wps_supplicant_fast_associate(iface);
3049 else
3050 return false;
3051 }
3052
3053 return true;
3054}
3055
3056
3057bool wpas_wps_partner_link_overlap_detect(struct wpa_supplicant *wpa_s)
3058{
3059 struct wpa_global *global = wpa_s->global;
3060 struct wpa_supplicant *iface;
3061
3062 for (iface = global->ifaces; iface; iface = iface->next) {
3063 if (iface == wpa_s)
3064 continue;
3065 if (iface->wps_overlap)
3066 return true;
3067 }
3068
3069 return false;
3070}
3071
3072
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003073void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid)
3074{
3075 struct wps_ap_info *ap;
Dmitry Shmidt051af732013-10-22 13:52:46 -07003076
3077 wpa_s->after_wps = 0;
3078
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003079 if (!wpa_s->wps_ap_iter)
3080 return;
3081 ap = wpas_wps_get_ap_info(wpa_s, bssid);
3082 if (ap == NULL)
3083 return;
3084 ap->tries++;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003085 os_get_reltime(&ap->last_attempt);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003086}