blob: fd0d14a87746b29deeebd9bf41b2f58d534045b2 [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"
29#include "blacklist.h"
30#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
42static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
43static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
44
45
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070046static void wpas_wps_clear_ap_info(struct wpa_supplicant *wpa_s)
47{
48 os_free(wpa_s->wps_ap);
49 wpa_s->wps_ap = NULL;
50 wpa_s->num_wps_ap = 0;
51 wpa_s->wps_ap_iter = 0;
52}
53
54
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -070055static void wpas_wps_assoc_with_cred(void *eloop_ctx, void *timeout_ctx)
56{
57 struct wpa_supplicant *wpa_s = eloop_ctx;
58 int use_fast_assoc = timeout_ctx != NULL;
59
60 wpa_printf(MSG_DEBUG, "WPS: Continuing association after eapol_cb");
61 if (!use_fast_assoc ||
62 wpa_supplicant_fast_associate(wpa_s) != 1)
63 wpa_supplicant_req_scan(wpa_s, 0, 0);
64}
65
66
67static void wpas_wps_assoc_with_cred_cancel(struct wpa_supplicant *wpa_s)
68{
69 eloop_cancel_timeout(wpas_wps_assoc_with_cred, wpa_s, (void *) 0);
70 eloop_cancel_timeout(wpas_wps_assoc_with_cred, wpa_s, (void *) 1);
71}
72
73
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070074int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
75{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080076 if (wpas_p2p_wps_eapol_cb(wpa_s) > 0)
77 return 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080078
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070079 if (!wpa_s->wps_success &&
80 wpa_s->current_ssid &&
81 eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
82 const u8 *bssid = wpa_s->bssid;
83 if (is_zero_ether_addr(bssid))
84 bssid = wpa_s->pending_bssid;
85
86 wpa_printf(MSG_DEBUG, "WPS: PIN registration with " MACSTR
87 " did not succeed - continue trying to find "
88 "suitable AP", MAC2STR(bssid));
89 wpa_blacklist_add(wpa_s, bssid);
90
91 wpa_supplicant_deauthenticate(wpa_s,
92 WLAN_REASON_DEAUTH_LEAVING);
93 wpa_s->reassociate = 1;
94 wpa_supplicant_req_scan(wpa_s,
95 wpa_s->blacklist_cleared ? 5 : 0, 0);
96 wpa_s->blacklist_cleared = 0;
97 return 1;
98 }
99
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700100 wpas_wps_clear_ap_info(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700101 eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
102 if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && !wpa_s->wps_success)
103 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL);
104
105 if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid &&
106 !(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
107 int disabled = wpa_s->current_ssid->disabled;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800108 unsigned int freq = wpa_s->assoc_freq;
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700109 struct wpa_bss *bss;
110 struct wpa_ssid *ssid = NULL;
111 int use_fast_assoc = 0;
112
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700113 wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800114 "try to associate with the received credential "
115 "(freq=%u)", freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700116 wpa_supplicant_deauthenticate(wpa_s,
117 WLAN_REASON_DEAUTH_LEAVING);
118 if (disabled) {
119 wpa_printf(MSG_DEBUG, "WPS: Current network is "
120 "disabled - wait for user to enable");
121 return 1;
122 }
123 wpa_s->after_wps = 5;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800124 wpa_s->wps_freq = freq;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800125 wpa_s->normal_scans = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700126 wpa_s->reassociate = 1;
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700127
128 wpa_printf(MSG_DEBUG, "WPS: Checking whether fast association "
129 "without a new scan can be used");
130 bss = wpa_supplicant_pick_network(wpa_s, &ssid);
131 if (bss) {
132 struct wpabuf *wps;
133 struct wps_parse_attr attr;
134
135 wps = wpa_bss_get_vendor_ie_multi(bss,
136 WPS_IE_VENDOR_TYPE);
137 if (wps && wps_parse_msg(wps, &attr) == 0 &&
138 attr.wps_state &&
139 *attr.wps_state == WPS_STATE_CONFIGURED)
140 use_fast_assoc = 1;
141 wpabuf_free(wps);
142 }
143
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -0700144 /*
145 * Complete the next step from an eloop timeout to allow pending
146 * driver events related to the disconnection to be processed
147 * first. This makes it less likely for disconnection event to
148 * cause problems with the following connection.
149 */
150 wpa_printf(MSG_DEBUG, "WPS: Continue association from timeout");
151 wpas_wps_assoc_with_cred_cancel(wpa_s);
152 eloop_register_timeout(0, 10000,
153 wpas_wps_assoc_with_cred, wpa_s,
154 use_fast_assoc ? (void *) 1 :
155 (void *) 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700156 return 1;
157 }
158
159 if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid) {
160 wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting "
161 "for external credential processing");
162 wpas_clear_wps(wpa_s);
163 wpa_supplicant_deauthenticate(wpa_s,
164 WLAN_REASON_DEAUTH_LEAVING);
165 return 1;
166 }
167
168 return 0;
169}
170
171
172static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
173 struct wpa_ssid *ssid,
174 const struct wps_credential *cred)
175{
176 struct wpa_driver_capa capa;
177 struct wpa_bss *bss;
178 const u8 *ie;
179 struct wpa_ie_data adv;
180 int wpa2 = 0, ccmp = 0;
181
182 /*
183 * Many existing WPS APs do not know how to negotiate WPA2 or CCMP in
184 * case they are configured for mixed mode operation (WPA+WPA2 and
185 * TKIP+CCMP). Try to use scan results to figure out whether the AP
186 * actually supports stronger security and select that if the client
187 * has support for it, too.
188 */
189
190 if (wpa_drv_get_capa(wpa_s, &capa))
191 return; /* Unknown what driver supports */
192
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800193 if (ssid->ssid == NULL)
194 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700195 bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len);
196 if (bss == NULL) {
197 wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS "
198 "table - use credential as-is");
199 return;
200 }
201
202 wpa_printf(MSG_DEBUG, "WPS: AP found from BSS table");
203
204 ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
205 if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0) {
206 wpa2 = 1;
207 if (adv.pairwise_cipher & WPA_CIPHER_CCMP)
208 ccmp = 1;
209 } else {
210 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
211 if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0 &&
212 adv.pairwise_cipher & WPA_CIPHER_CCMP)
213 ccmp = 1;
214 }
215
216 if (ie == NULL && (ssid->proto & WPA_PROTO_WPA) &&
217 (ssid->pairwise_cipher & WPA_CIPHER_TKIP)) {
218 /*
219 * TODO: This could be the initial AP configuration and the
220 * Beacon contents could change shortly. Should request a new
221 * scan and delay addition of the network until the updated
222 * scan results are available.
223 */
224 wpa_printf(MSG_DEBUG, "WPS: The AP did not yet advertise WPA "
225 "support - use credential as-is");
226 return;
227 }
228
229 if (ccmp && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
230 (ssid->pairwise_cipher & WPA_CIPHER_TKIP) &&
231 (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
232 wpa_printf(MSG_DEBUG, "WPS: Add CCMP into the credential "
233 "based on scan results");
234 if (wpa_s->conf->ap_scan == 1)
235 ssid->pairwise_cipher |= WPA_CIPHER_CCMP;
236 else
237 ssid->pairwise_cipher = WPA_CIPHER_CCMP;
238 }
239
240 if (wpa2 && !(ssid->proto & WPA_PROTO_RSN) &&
241 (ssid->proto & WPA_PROTO_WPA) &&
242 (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP)) {
243 wpa_printf(MSG_DEBUG, "WPS: Add WPA2 into the credential "
244 "based on scan results");
245 if (wpa_s->conf->ap_scan == 1)
246 ssid->proto |= WPA_PROTO_RSN;
247 else
248 ssid->proto = WPA_PROTO_RSN;
249 }
250}
251
252
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -0700253static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s,
254 struct wpa_ssid *new_ssid)
255{
256 struct wpa_ssid *ssid, *next;
257
258 for (ssid = wpa_s->conf->ssid, next = ssid ? ssid->next : NULL; ssid;
259 ssid = next, next = ssid ? ssid->next : NULL) {
260 /*
261 * new_ssid has already been added to the list in
262 * wpas_wps_add_network(), so skip it.
263 */
264 if (ssid == new_ssid)
265 continue;
266
267 if (ssid->bssid_set || new_ssid->bssid_set) {
268 if (ssid->bssid_set != new_ssid->bssid_set)
269 continue;
270 if (os_memcmp(ssid->bssid, new_ssid->bssid, ETH_ALEN) !=
271 0)
272 continue;
273 }
274
275 /* compare SSID */
276 if (ssid->ssid_len == 0 || ssid->ssid_len != new_ssid->ssid_len)
277 continue;
278
279 if (ssid->ssid && new_ssid->ssid) {
280 if (os_memcmp(ssid->ssid, new_ssid->ssid,
281 ssid->ssid_len) != 0)
282 continue;
283 } else if (ssid->ssid || new_ssid->ssid)
284 continue;
285
286 /* compare security parameters */
287 if (ssid->auth_alg != new_ssid->auth_alg ||
288 ssid->key_mgmt != new_ssid->key_mgmt ||
289 ssid->proto != new_ssid->proto ||
290 ssid->pairwise_cipher != new_ssid->pairwise_cipher ||
291 ssid->group_cipher != new_ssid->group_cipher)
292 continue;
293
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -0700294 /* Remove the duplicated older network entry. */
295 wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id);
296 wpas_notify_network_removed(wpa_s, ssid);
297 wpa_config_remove_network(wpa_s->conf, ssid->id);
298 }
299}
300
301
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700302static int wpa_supplicant_wps_cred(void *ctx,
303 const struct wps_credential *cred)
304{
305 struct wpa_supplicant *wpa_s = ctx;
306 struct wpa_ssid *ssid = wpa_s->current_ssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700307 u16 auth_type;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800308#ifdef CONFIG_WPS_REG_DISABLE_OPEN
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700309 int registrar = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800310#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700311
312 if ((wpa_s->conf->wps_cred_processing == 1 ||
313 wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) {
314 size_t blen = cred->cred_attr_len * 2 + 1;
315 char *buf = os_malloc(blen);
316 if (buf) {
317 wpa_snprintf_hex(buf, blen,
318 cred->cred_attr, cred->cred_attr_len);
319 wpa_msg(wpa_s, MSG_INFO, "%s%s",
320 WPS_EVENT_CRED_RECEIVED, buf);
321 os_free(buf);
322 }
323
324 wpas_notify_wps_credential(wpa_s, cred);
325 } else
326 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED);
327
328 wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
329 cred->cred_attr, cred->cred_attr_len);
330
331 if (wpa_s->conf->wps_cred_processing == 1)
332 return 0;
333
334 wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
335 wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
336 cred->auth_type);
337 wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
338 wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
339 wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
340 cred->key, cred->key_len);
341 wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
342 MAC2STR(cred->mac_addr));
343
344 auth_type = cred->auth_type;
345 if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
346 wpa_printf(MSG_DEBUG, "WPS: Workaround - convert mixed-mode "
347 "auth_type into WPA2PSK");
348 auth_type = WPS_AUTH_WPA2PSK;
349 }
350
351 if (auth_type != WPS_AUTH_OPEN &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700352 auth_type != WPS_AUTH_WPAPSK &&
353 auth_type != WPS_AUTH_WPA2PSK) {
354 wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
355 "unsupported authentication type 0x%x",
356 auth_type);
357 return 0;
358 }
359
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800360 if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) {
361 if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) {
362 wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with "
363 "invalid Network Key length %lu",
364 (unsigned long) cred->key_len);
365 return -1;
366 }
367 }
368
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700369 if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
370 wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
371 "on the received credential");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800372#ifdef CONFIG_WPS_REG_DISABLE_OPEN
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700373 if (ssid->eap.identity &&
374 ssid->eap.identity_len == WSC_ID_REGISTRAR_LEN &&
375 os_memcmp(ssid->eap.identity, WSC_ID_REGISTRAR,
376 WSC_ID_REGISTRAR_LEN) == 0)
377 registrar = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800378#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700379 os_free(ssid->eap.identity);
380 ssid->eap.identity = NULL;
381 ssid->eap.identity_len = 0;
382 os_free(ssid->eap.phase1);
383 ssid->eap.phase1 = NULL;
384 os_free(ssid->eap.eap_methods);
385 ssid->eap.eap_methods = NULL;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700386 if (!ssid->p2p_group) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700387 ssid->temporary = 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700388 ssid->bssid_set = 0;
389 }
390 ssid->disabled_until.sec = 0;
391 ssid->disabled_until.usec = 0;
392 ssid->auth_failures = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700393 } else {
394 wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
395 "received credential");
396 ssid = wpa_config_add_network(wpa_s->conf);
397 if (ssid == NULL)
398 return -1;
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -0700399 if (wpa_s->current_ssid) {
400 /*
401 * Should the GO issue multiple credentials for some
402 * reason, each credential should be marked as a
403 * temporary P2P group similarly to the one that gets
404 * marked as such based on the pre-configured values
405 * used for the WPS network block.
406 */
407 ssid->p2p_group = wpa_s->current_ssid->p2p_group;
408 ssid->temporary = wpa_s->current_ssid->temporary;
409 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700410 wpas_notify_network_added(wpa_s, ssid);
411 }
412
413 wpa_config_set_network_defaults(ssid);
414
415 os_free(ssid->ssid);
416 ssid->ssid = os_malloc(cred->ssid_len);
417 if (ssid->ssid) {
418 os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len);
419 ssid->ssid_len = cred->ssid_len;
420 }
421
422 switch (cred->encr_type) {
423 case WPS_ENCR_NONE:
424 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700425 case WPS_ENCR_TKIP:
426 ssid->pairwise_cipher = WPA_CIPHER_TKIP;
427 break;
428 case WPS_ENCR_AES:
429 ssid->pairwise_cipher = WPA_CIPHER_CCMP;
430 break;
431 }
432
433 switch (auth_type) {
434 case WPS_AUTH_OPEN:
435 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
436 ssid->key_mgmt = WPA_KEY_MGMT_NONE;
437 ssid->proto = 0;
438#ifdef CONFIG_WPS_REG_DISABLE_OPEN
439 if (registrar) {
440 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OPEN_NETWORK
441 "id=%d - Credentials for an open "
442 "network disabled by default - use "
443 "'select_network %d' to enable",
444 ssid->id, ssid->id);
445 ssid->disabled = 1;
446 }
447#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
448 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700449 case WPS_AUTH_WPAPSK:
450 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
451 ssid->key_mgmt = WPA_KEY_MGMT_PSK;
452 ssid->proto = WPA_PROTO_WPA;
453 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700454 case WPS_AUTH_WPA2PSK:
455 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
456 ssid->key_mgmt = WPA_KEY_MGMT_PSK;
457 ssid->proto = WPA_PROTO_RSN;
458 break;
459 }
460
461 if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) {
462 if (cred->key_len == 2 * PMK_LEN) {
463 if (hexstr2bin((const char *) cred->key, ssid->psk,
464 PMK_LEN)) {
465 wpa_printf(MSG_ERROR, "WPS: Invalid Network "
466 "Key");
467 return -1;
468 }
469 ssid->psk_set = 1;
470 ssid->export_keys = 1;
471 } else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) {
472 os_free(ssid->passphrase);
473 ssid->passphrase = os_malloc(cred->key_len + 1);
474 if (ssid->passphrase == NULL)
475 return -1;
476 os_memcpy(ssid->passphrase, cred->key, cred->key_len);
477 ssid->passphrase[cred->key_len] = '\0';
478 wpa_config_update_psk(ssid);
479 ssid->export_keys = 1;
480 } else {
481 wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
482 "length %lu",
483 (unsigned long) cred->key_len);
484 return -1;
485 }
486 }
487
488 wpas_wps_security_workaround(wpa_s, ssid, cred);
489
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -0700490 wpas_wps_remove_dup_network(wpa_s, ssid);
491
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700492#ifndef CONFIG_NO_CONFIG_WRITE
493 if (wpa_s->conf->update_config &&
494 wpa_config_write(wpa_s->confname, wpa_s->conf)) {
495 wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration");
496 return -1;
497 }
498#endif /* CONFIG_NO_CONFIG_WRITE */
499
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800500 /*
501 * Optimize the post-WPS scan based on the channel used during
502 * the provisioning in case EAP-Failure is not received.
503 */
504 wpa_s->after_wps = 5;
505 wpa_s->wps_freq = wpa_s->assoc_freq;
506
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700507 return 0;
508}
509
510
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700511static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
512 struct wps_event_m2d *m2d)
513{
514 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_M2D
515 "dev_password_id=%d config_error=%d",
516 m2d->dev_password_id, m2d->config_error);
517 wpas_notify_wps_event_m2d(wpa_s, m2d);
518#ifdef CONFIG_P2P
519 if (wpa_s->parent && wpa_s->parent != wpa_s) {
520 wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_M2D
521 "dev_password_id=%d config_error=%d",
522 m2d->dev_password_id, m2d->config_error);
523 }
524 if (m2d->config_error == WPS_CFG_MULTIPLE_PBC_DETECTED) {
525 /*
526 * Notify P2P from eloop timeout to avoid issues with the
527 * interface getting removed while processing a message.
528 */
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -0700529 eloop_register_timeout(0, 0, wpas_p2p_pbc_overlap_cb, wpa_s,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700530 NULL);
531 }
532#endif /* CONFIG_P2P */
533}
534
535
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700536static void wpas_wps_clear_timeout(void *eloop_ctx, void *timeout_ctx)
537{
538 struct wpa_supplicant *wpa_s = eloop_ctx;
539 wpa_printf(MSG_DEBUG, "WPS: Clear WPS network from timeout");
540 wpas_clear_wps(wpa_s);
541}
542
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700543
544static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
545 struct wps_event_fail *fail)
546{
547 if (fail->error_indication > 0 &&
548 fail->error_indication < NUM_WPS_EI_VALUES) {
549 wpa_msg(wpa_s, MSG_INFO,
550 WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
551 fail->msg, fail->config_error, fail->error_indication,
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700552 wps_ei_str(fail->error_indication));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700553 if (wpa_s->parent && wpa_s->parent != wpa_s)
554 wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
555 "msg=%d config_error=%d reason=%d (%s)",
556 fail->msg, fail->config_error,
557 fail->error_indication,
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700558 wps_ei_str(fail->error_indication));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700559 } else {
560 wpa_msg(wpa_s, MSG_INFO,
561 WPS_EVENT_FAIL "msg=%d config_error=%d",
562 fail->msg, fail->config_error);
563 if (wpa_s->parent && wpa_s->parent != wpa_s)
564 wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
565 "msg=%d config_error=%d",
566 fail->msg, fail->config_error);
567 }
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700568
569 /*
570 * Need to allow WPS processing to complete, e.g., by sending WSC_NACK.
571 */
572 wpa_printf(MSG_DEBUG, "WPS: Register timeout to clear WPS network");
573 eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
574 eloop_register_timeout(0, 100000, wpas_wps_clear_timeout, wpa_s, NULL);
575
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700576 wpas_notify_wps_event_fail(wpa_s, fail);
Jouni Malinen75ecf522011-06-27 15:19:46 -0700577 wpas_p2p_wps_failed(wpa_s, fail);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700578}
579
580
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800581static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx);
582
583static void wpas_wps_reenable_networks(struct wpa_supplicant *wpa_s)
584{
585 struct wpa_ssid *ssid;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800586 int changed = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800587
588 eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
589
590 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
591 if (ssid->disabled_for_connect && ssid->disabled) {
592 ssid->disabled_for_connect = 0;
593 ssid->disabled = 0;
594 wpas_notify_network_enabled_changed(wpa_s, ssid);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800595 changed++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800596 }
597 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800598
599 if (changed) {
600#ifndef CONFIG_NO_CONFIG_WRITE
601 if (wpa_s->conf->update_config &&
602 wpa_config_write(wpa_s->confname, wpa_s->conf)) {
603 wpa_printf(MSG_DEBUG, "WPS: Failed to update "
604 "configuration");
605 }
606#endif /* CONFIG_NO_CONFIG_WRITE */
607 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800608}
609
610
611static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx)
612{
613 struct wpa_supplicant *wpa_s = eloop_ctx;
614 /* Enable the networks disabled during wpas_wps_reassoc */
615 wpas_wps_reenable_networks(wpa_s);
616}
617
618
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700619static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
620{
621 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
622 wpa_s->wps_success = 1;
623 wpas_notify_wps_event_success(wpa_s);
Dmitry Shmidt44c95782013-05-17 09:51:35 -0700624 if (wpa_s->current_ssid)
625 wpas_clear_temp_disabled(wpa_s, wpa_s->current_ssid, 1);
626 wpa_s->extra_blacklist_count = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800627
628 /*
629 * Enable the networks disabled during wpas_wps_reassoc after 10
630 * seconds. The 10 seconds timer is to allow the data connection to be
631 * formed before allowing other networks to be selected.
632 */
633 eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
634 NULL);
635
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700636 wpas_p2p_wps_success(wpa_s, wpa_s->bssid, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700637}
638
639
640static void wpa_supplicant_wps_event_er_ap_add(struct wpa_supplicant *wpa_s,
641 struct wps_event_er_ap *ap)
642{
643 char uuid_str[100];
644 char dev_type[WPS_DEV_TYPE_BUFSIZE];
645
646 uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str));
647 if (ap->pri_dev_type)
648 wps_dev_type_bin2str(ap->pri_dev_type, dev_type,
649 sizeof(dev_type));
650 else
651 dev_type[0] = '\0';
652
653 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_ADD "%s " MACSTR
654 " pri_dev_type=%s wps_state=%d |%s|%s|%s|%s|%s|%s|",
655 uuid_str, MAC2STR(ap->mac_addr), dev_type, ap->wps_state,
656 ap->friendly_name ? ap->friendly_name : "",
657 ap->manufacturer ? ap->manufacturer : "",
658 ap->model_description ? ap->model_description : "",
659 ap->model_name ? ap->model_name : "",
660 ap->manufacturer_url ? ap->manufacturer_url : "",
661 ap->model_url ? ap->model_url : "");
662}
663
664
665static void wpa_supplicant_wps_event_er_ap_remove(struct wpa_supplicant *wpa_s,
666 struct wps_event_er_ap *ap)
667{
668 char uuid_str[100];
669 uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str));
670 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_REMOVE "%s", uuid_str);
671}
672
673
674static void wpa_supplicant_wps_event_er_enrollee_add(
675 struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee)
676{
677 char uuid_str[100];
678 char dev_type[WPS_DEV_TYPE_BUFSIZE];
679
680 uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str));
681 if (enrollee->pri_dev_type)
682 wps_dev_type_bin2str(enrollee->pri_dev_type, dev_type,
683 sizeof(dev_type));
684 else
685 dev_type[0] = '\0';
686
687 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_ADD "%s " MACSTR
688 " M1=%d config_methods=0x%x dev_passwd_id=%d pri_dev_type=%s "
689 "|%s|%s|%s|%s|%s|",
690 uuid_str, MAC2STR(enrollee->mac_addr), enrollee->m1_received,
691 enrollee->config_methods, enrollee->dev_passwd_id, dev_type,
692 enrollee->dev_name ? enrollee->dev_name : "",
693 enrollee->manufacturer ? enrollee->manufacturer : "",
694 enrollee->model_name ? enrollee->model_name : "",
695 enrollee->model_number ? enrollee->model_number : "",
696 enrollee->serial_number ? enrollee->serial_number : "");
697}
698
699
700static void wpa_supplicant_wps_event_er_enrollee_remove(
701 struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee)
702{
703 char uuid_str[100];
704 uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str));
705 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_REMOVE "%s " MACSTR,
706 uuid_str, MAC2STR(enrollee->mac_addr));
707}
708
709
710static void wpa_supplicant_wps_event_er_ap_settings(
711 struct wpa_supplicant *wpa_s,
712 struct wps_event_er_ap_settings *ap_settings)
713{
714 char uuid_str[100];
715 char key_str[65];
716 const struct wps_credential *cred = ap_settings->cred;
717
718 key_str[0] = '\0';
719 if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
720 if (cred->key_len >= 8 && cred->key_len <= 64) {
721 os_memcpy(key_str, cred->key, cred->key_len);
722 key_str[cred->key_len] = '\0';
723 }
724 }
725
726 uuid_bin2str(ap_settings->uuid, uuid_str, sizeof(uuid_str));
727 /* Use wpa_msg_ctrl to avoid showing the key in debug log */
728 wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_SETTINGS
729 "uuid=%s ssid=%s auth_type=0x%04x encr_type=0x%04x "
730 "key=%s",
731 uuid_str, wpa_ssid_txt(cred->ssid, cred->ssid_len),
732 cred->auth_type, cred->encr_type, key_str);
733}
734
735
736static void wpa_supplicant_wps_event_er_set_sel_reg(
737 struct wpa_supplicant *wpa_s,
738 struct wps_event_er_set_selected_registrar *ev)
739{
740 char uuid_str[100];
741
742 uuid_bin2str(ev->uuid, uuid_str, sizeof(uuid_str));
743 switch (ev->state) {
744 case WPS_ER_SET_SEL_REG_START:
745 wpa_msg(wpa_s, MSG_DEBUG, WPS_EVENT_ER_SET_SEL_REG
746 "uuid=%s state=START sel_reg=%d dev_passwd_id=%u "
747 "sel_reg_config_methods=0x%x",
748 uuid_str, ev->sel_reg, ev->dev_passwd_id,
749 ev->sel_reg_config_methods);
750 break;
751 case WPS_ER_SET_SEL_REG_DONE:
752 wpa_msg(wpa_s, MSG_DEBUG, WPS_EVENT_ER_SET_SEL_REG
753 "uuid=%s state=DONE", uuid_str);
754 break;
755 case WPS_ER_SET_SEL_REG_FAILED:
756 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_SET_SEL_REG
757 "uuid=%s state=FAILED", uuid_str);
758 break;
759 }
760}
761
762
763static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
764 union wps_event_data *data)
765{
766 struct wpa_supplicant *wpa_s = ctx;
767 switch (event) {
768 case WPS_EV_M2D:
769 wpa_supplicant_wps_event_m2d(wpa_s, &data->m2d);
770 break;
771 case WPS_EV_FAIL:
772 wpa_supplicant_wps_event_fail(wpa_s, &data->fail);
773 break;
774 case WPS_EV_SUCCESS:
775 wpa_supplicant_wps_event_success(wpa_s);
776 break;
777 case WPS_EV_PWD_AUTH_FAIL:
778#ifdef CONFIG_AP
779 if (wpa_s->ap_iface && data->pwd_auth_fail.enrollee)
780 wpa_supplicant_ap_pwd_auth_fail(wpa_s);
781#endif /* CONFIG_AP */
782 break;
783 case WPS_EV_PBC_OVERLAP:
784 break;
785 case WPS_EV_PBC_TIMEOUT:
786 break;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700787 case WPS_EV_PBC_ACTIVE:
788 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ACTIVE);
789 break;
790 case WPS_EV_PBC_DISABLE:
791 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_DISABLE);
792 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700793 case WPS_EV_ER_AP_ADD:
794 wpa_supplicant_wps_event_er_ap_add(wpa_s, &data->ap);
795 break;
796 case WPS_EV_ER_AP_REMOVE:
797 wpa_supplicant_wps_event_er_ap_remove(wpa_s, &data->ap);
798 break;
799 case WPS_EV_ER_ENROLLEE_ADD:
800 wpa_supplicant_wps_event_er_enrollee_add(wpa_s,
801 &data->enrollee);
802 break;
803 case WPS_EV_ER_ENROLLEE_REMOVE:
804 wpa_supplicant_wps_event_er_enrollee_remove(wpa_s,
805 &data->enrollee);
806 break;
807 case WPS_EV_ER_AP_SETTINGS:
808 wpa_supplicant_wps_event_er_ap_settings(wpa_s,
809 &data->ap_settings);
810 break;
811 case WPS_EV_ER_SET_SELECTED_REGISTRAR:
812 wpa_supplicant_wps_event_er_set_sel_reg(wpa_s,
813 &data->set_sel_reg);
814 break;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800815 case WPS_EV_AP_PIN_SUCCESS:
816 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700817 }
818}
819
820
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700821static int wpa_supplicant_wps_rf_band(void *ctx)
822{
823 struct wpa_supplicant *wpa_s = ctx;
824
825 if (!wpa_s->current_ssid || !wpa_s->assoc_freq)
826 return 0;
827
828 return (wpa_s->assoc_freq > 2484) ? WPS_RF_50GHZ : WPS_RF_24GHZ;
829}
830
831
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700832enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid)
833{
834 if (eap_is_wps_pbc_enrollee(&ssid->eap) ||
835 eap_is_wps_pin_enrollee(&ssid->eap))
836 return WPS_REQ_ENROLLEE;
837 else
838 return WPS_REQ_REGISTRAR;
839}
840
841
842static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
843{
844 int id;
Jouni Malinen75ecf522011-06-27 15:19:46 -0700845 struct wpa_ssid *ssid, *remove_ssid = NULL, *prev_current;
846
Dmitry Shmidt051af732013-10-22 13:52:46 -0700847 wpa_s->after_wps = 0;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700848 wpa_s->known_wps_freq = 0;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700849
Jouni Malinen75ecf522011-06-27 15:19:46 -0700850 prev_current = wpa_s->current_ssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700851
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800852 /* Enable the networks disabled during wpas_wps_reassoc */
853 wpas_wps_reenable_networks(wpa_s);
854
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700855 eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800856 eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700857
858 /* Remove any existing WPS network from configuration */
859 ssid = wpa_s->conf->ssid;
860 while (ssid) {
861 if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
862 if (ssid == wpa_s->current_ssid) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700863 wpa_supplicant_deauthenticate(
864 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700865 }
866 id = ssid->id;
867 remove_ssid = ssid;
868 } else
869 id = -1;
870 ssid = ssid->next;
871 if (id >= 0) {
Jouni Malinen75ecf522011-06-27 15:19:46 -0700872 if (prev_current == remove_ssid) {
873 wpa_sm_set_config(wpa_s->wpa, NULL);
874 eapol_sm_notify_config(wpa_s->eapol, NULL,
875 NULL);
876 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700877 wpas_notify_network_removed(wpa_s, remove_ssid);
878 wpa_config_remove_network(wpa_s->conf, id);
879 }
880 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700881
882 wpas_wps_clear_ap_info(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700883}
884
885
886static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
887{
888 struct wpa_supplicant *wpa_s = eloop_ctx;
889 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed "
890 "out");
891 wpas_clear_wps(wpa_s);
892}
893
894
895static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
Dmitry Shmidtcf32e602014-01-28 10:57:39 -0800896 int registrar, const u8 *dev_addr,
897 const u8 *bssid)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700898{
899 struct wpa_ssid *ssid;
900
901 ssid = wpa_config_add_network(wpa_s->conf);
902 if (ssid == NULL)
903 return NULL;
904 wpas_notify_network_added(wpa_s, ssid);
905 wpa_config_set_network_defaults(ssid);
906 ssid->temporary = 1;
907 if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 ||
908 wpa_config_set(ssid, "eap", "WSC", 0) < 0 ||
909 wpa_config_set(ssid, "identity", registrar ?
910 "\"" WSC_ID_REGISTRAR "\"" :
911 "\"" WSC_ID_ENROLLEE "\"", 0) < 0) {
912 wpas_notify_network_removed(wpa_s, ssid);
913 wpa_config_remove_network(wpa_s->conf, ssid->id);
914 return NULL;
915 }
916
Dmitry Shmidtcf32e602014-01-28 10:57:39 -0800917#ifdef CONFIG_P2P
918 if (dev_addr)
919 os_memcpy(ssid->go_p2p_dev_addr, dev_addr, ETH_ALEN);
920#endif /* CONFIG_P2P */
921
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700922 if (bssid) {
923#ifndef CONFIG_P2P
924 struct wpa_bss *bss;
925 int count = 0;
926#endif /* CONFIG_P2P */
927
928 os_memcpy(ssid->bssid, bssid, ETH_ALEN);
929 ssid->bssid_set = 1;
930
931 /*
932 * Note: With P2P, the SSID may change at the time the WPS
933 * provisioning is started, so better not filter the AP based
934 * on the current SSID in the scan results.
935 */
936#ifndef CONFIG_P2P
937 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
938 if (os_memcmp(bssid, bss->bssid, ETH_ALEN) != 0)
939 continue;
940
941 os_free(ssid->ssid);
942 ssid->ssid = os_malloc(bss->ssid_len);
943 if (ssid->ssid == NULL)
944 break;
945 os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
946 ssid->ssid_len = bss->ssid_len;
947 wpa_hexdump_ascii(MSG_DEBUG, "WPS: Picked SSID from "
948 "scan results",
949 ssid->ssid, ssid->ssid_len);
950 count++;
951 }
952
953 if (count > 1) {
954 wpa_printf(MSG_DEBUG, "WPS: More than one SSID found "
955 "for the AP; use wildcard");
956 os_free(ssid->ssid);
957 ssid->ssid = NULL;
958 ssid->ssid_len = 0;
959 }
960#endif /* CONFIG_P2P */
961 }
962
963 return ssid;
964}
965
966
Dmitry Shmidt44c95782013-05-17 09:51:35 -0700967static void wpas_wps_temp_disable(struct wpa_supplicant *wpa_s,
968 struct wpa_ssid *selected)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700969{
970 struct wpa_ssid *ssid;
971
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800972 if (wpa_s->current_ssid)
973 wpa_supplicant_deauthenticate(
974 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
975
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700976 /* Mark all other networks disabled and trigger reassociation */
977 ssid = wpa_s->conf->ssid;
978 while (ssid) {
979 int was_disabled = ssid->disabled;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800980 ssid->disabled_for_connect = 0;
Jouni Malinen75ecf522011-06-27 15:19:46 -0700981 /*
982 * In case the network object corresponds to a persistent group
983 * then do not send out network disabled signal. In addition,
984 * do not change disabled status of persistent network objects
985 * from 2 to 1 should we connect to another network.
986 */
987 if (was_disabled != 2) {
988 ssid->disabled = ssid != selected;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800989 if (was_disabled != ssid->disabled) {
990 if (ssid->disabled)
991 ssid->disabled_for_connect = 1;
Jouni Malinen75ecf522011-06-27 15:19:46 -0700992 wpas_notify_network_enabled_changed(wpa_s,
993 ssid);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800994 }
Jouni Malinen75ecf522011-06-27 15:19:46 -0700995 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700996 ssid = ssid->next;
997 }
Dmitry Shmidt44c95782013-05-17 09:51:35 -0700998}
999
1000
1001static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001002 struct wpa_ssid *selected, const u8 *bssid,
1003 int freq)
Dmitry Shmidt44c95782013-05-17 09:51:35 -07001004{
1005 struct wpa_bss *bss;
1006
1007 wpa_s->after_wps = 0;
1008 wpa_s->known_wps_freq = 0;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001009 if (freq) {
1010 wpa_s->after_wps = 5;
1011 wpa_s->wps_freq = freq;
1012 } else if (bssid) {
Dmitry Shmidt44c95782013-05-17 09:51:35 -07001013 bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
1014 if (bss && bss->freq > 0) {
1015 wpa_s->known_wps_freq = 1;
1016 wpa_s->wps_freq = bss->freq;
1017 }
1018 }
1019
1020 wpas_wps_temp_disable(wpa_s, selected);
1021
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001022 wpa_s->disconnected = 0;
1023 wpa_s->reassociate = 1;
1024 wpa_s->scan_runs = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001025 wpa_s->normal_scans = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001026 wpa_s->wps_success = 0;
1027 wpa_s->blacklist_cleared = 0;
Dmitry Shmidtfa3fc4a2013-11-21 13:34:38 -08001028
1029 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001030 wpa_supplicant_req_scan(wpa_s, 0, 0);
1031}
1032
1033
1034int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
1035 int p2p_group)
1036{
1037 struct wpa_ssid *ssid;
1038 wpas_clear_wps(wpa_s);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001039 ssid = wpas_wps_add_network(wpa_s, 0, NULL, bssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001040 if (ssid == NULL)
1041 return -1;
1042 ssid->temporary = 1;
1043 ssid->p2p_group = p2p_group;
1044#ifdef CONFIG_P2P
1045 if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
1046 ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
1047 if (ssid->ssid) {
1048 ssid->ssid_len = wpa_s->go_params->ssid_len;
1049 os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
1050 ssid->ssid_len);
1051 wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
1052 "SSID", ssid->ssid, ssid->ssid_len);
1053 }
1054 }
1055#endif /* CONFIG_P2P */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001056 if (wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0) < 0)
1057 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001058 if (wpa_s->wps_fragment_size)
1059 ssid->eap.fragment_size = wpa_s->wps_fragment_size;
1060 eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
1061 wpa_s, NULL);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001062 wpas_wps_reassoc(wpa_s, ssid, bssid, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001063 return 0;
1064}
1065
1066
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001067static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
1068 const u8 *dev_addr, const u8 *bssid,
1069 const char *pin, int p2p_group, u16 dev_pw_id,
1070 const u8 *peer_pubkey_hash,
1071 const u8 *ssid_val, size_t ssid_len, int freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001072{
1073 struct wpa_ssid *ssid;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001074 char val[128 + 2 * WPS_OOB_PUBKEY_HASH_LEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001075 unsigned int rpin = 0;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001076 char hash[2 * WPS_OOB_PUBKEY_HASH_LEN + 10];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001077
1078 wpas_clear_wps(wpa_s);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001079 if (bssid && is_zero_ether_addr(bssid))
1080 bssid = NULL;
1081 ssid = wpas_wps_add_network(wpa_s, 0, dev_addr, bssid);
1082 if (ssid == NULL) {
1083 wpa_printf(MSG_DEBUG, "WPS: Could not add network");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001084 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001085 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001086 ssid->temporary = 1;
1087 ssid->p2p_group = p2p_group;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001088 if (ssid_val) {
1089 ssid->ssid = os_malloc(ssid_len);
1090 if (ssid->ssid) {
1091 os_memcpy(ssid->ssid, ssid_val, ssid_len);
1092 ssid->ssid_len = ssid_len;
1093 }
1094 }
1095 if (peer_pubkey_hash) {
1096 os_memcpy(hash, " pkhash=", 8);
1097 wpa_snprintf_hex_uppercase(hash + 8, sizeof(hash) - 8,
1098 peer_pubkey_hash,
1099 WPS_OOB_PUBKEY_HASH_LEN);
1100 } else {
1101 hash[0] = '\0';
1102 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001103#ifdef CONFIG_P2P
1104 if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
1105 ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
1106 if (ssid->ssid) {
1107 ssid->ssid_len = wpa_s->go_params->ssid_len;
1108 os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
1109 ssid->ssid_len);
1110 wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
1111 "SSID", ssid->ssid, ssid->ssid_len);
1112 }
1113 }
1114#endif /* CONFIG_P2P */
1115 if (pin)
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001116 os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u%s\"",
1117 pin, dev_pw_id, hash);
1118 else if (pin == NULL && dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) {
1119 os_snprintf(val, sizeof(val), "\"dev_pw_id=%u%s\"",
1120 dev_pw_id, hash);
1121 } else {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001122 rpin = wps_generate_pin();
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001123 os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u%s\"",
1124 rpin, dev_pw_id, hash);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001125 }
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001126 if (wpa_config_set(ssid, "phase1", val, 0) < 0) {
1127 wpa_printf(MSG_DEBUG, "WPS: Failed to set phase1 '%s'", val);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001128 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001129 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001130 if (wpa_s->wps_fragment_size)
1131 ssid->eap.fragment_size = wpa_s->wps_fragment_size;
1132 eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
1133 wpa_s, NULL);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001134 wpa_s->wps_ap_iter = 1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001135 wpas_wps_reassoc(wpa_s, ssid, bssid, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001136 return rpin;
1137}
1138
1139
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001140int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
1141 const char *pin, int p2p_group, u16 dev_pw_id)
1142{
1143 return wpas_wps_start_dev_pw(wpa_s, NULL, bssid, pin, p2p_group,
1144 dev_pw_id, NULL, NULL, 0, 0);
1145}
1146
1147
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001148/* Cancel the wps pbc/pin requests */
1149int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
1150{
1151#ifdef CONFIG_AP
1152 if (wpa_s->ap_iface) {
1153 wpa_printf(MSG_DEBUG, "WPS: Cancelling in AP mode");
1154 return wpa_supplicant_ap_wps_cancel(wpa_s);
1155 }
1156#endif /* CONFIG_AP */
1157
Dmitry Shmidt04949592012-07-19 12:16:46 -07001158 if (wpa_s->wpa_state == WPA_SCANNING ||
1159 wpa_s->wpa_state == WPA_DISCONNECTED) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001160 wpa_printf(MSG_DEBUG, "WPS: Cancel operation - cancel scan");
1161 wpa_supplicant_cancel_scan(wpa_s);
1162 wpas_clear_wps(wpa_s);
1163 } else if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
1164 wpa_printf(MSG_DEBUG, "WPS: Cancel operation - "
1165 "deauthenticate");
1166 wpa_supplicant_deauthenticate(wpa_s,
1167 WLAN_REASON_DEAUTH_LEAVING);
1168 wpas_clear_wps(wpa_s);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001169 } else {
1170 wpas_wps_reenable_networks(wpa_s);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001171 wpas_wps_clear_ap_info(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001172 if (eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL) >
1173 0)
1174 wpas_clear_wps(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001175 }
1176
Dmitry Shmidt051af732013-10-22 13:52:46 -07001177 wpa_s->after_wps = 0;
1178
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001179 return 0;
1180}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001181
1182
1183int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
1184 const char *pin, struct wps_new_ap_settings *settings)
1185{
1186 struct wpa_ssid *ssid;
1187 char val[200];
1188 char *pos, *end;
1189 int res;
1190
1191 if (!pin)
1192 return -1;
1193 wpas_clear_wps(wpa_s);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001194 ssid = wpas_wps_add_network(wpa_s, 1, NULL, bssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001195 if (ssid == NULL)
1196 return -1;
1197 ssid->temporary = 1;
1198 pos = val;
1199 end = pos + sizeof(val);
1200 res = os_snprintf(pos, end - pos, "\"pin=%s", pin);
1201 if (res < 0 || res >= end - pos)
1202 return -1;
1203 pos += res;
1204 if (settings) {
1205 res = os_snprintf(pos, end - pos, " new_ssid=%s new_auth=%s "
1206 "new_encr=%s new_key=%s",
1207 settings->ssid_hex, settings->auth,
1208 settings->encr, settings->key_hex);
1209 if (res < 0 || res >= end - pos)
1210 return -1;
1211 pos += res;
1212 }
1213 res = os_snprintf(pos, end - pos, "\"");
1214 if (res < 0 || res >= end - pos)
1215 return -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001216 if (wpa_config_set(ssid, "phase1", val, 0) < 0)
1217 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001218 if (wpa_s->wps_fragment_size)
1219 ssid->eap.fragment_size = wpa_s->wps_fragment_size;
1220 eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
1221 wpa_s, NULL);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001222 wpas_wps_reassoc(wpa_s, ssid, bssid, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001223 return 0;
1224}
1225
1226
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001227static int wpas_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
1228 const u8 *p2p_dev_addr, const u8 *psk,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001229 size_t psk_len)
1230{
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001231 if (is_zero_ether_addr(p2p_dev_addr)) {
1232 wpa_printf(MSG_DEBUG,
1233 "Received new WPA/WPA2-PSK from WPS for STA " MACSTR,
1234 MAC2STR(mac_addr));
1235 } else {
1236 wpa_printf(MSG_DEBUG,
1237 "Received new WPA/WPA2-PSK from WPS for STA " MACSTR
1238 " P2P Device Addr " MACSTR,
1239 MAC2STR(mac_addr), MAC2STR(p2p_dev_addr));
1240 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001241 wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
1242
1243 /* TODO */
1244
1245 return 0;
1246}
1247
1248
1249static void wpas_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
1250 const struct wps_device_data *dev)
1251{
1252 char uuid[40], txt[400];
1253 int len;
1254 char devtype[WPS_DEV_TYPE_BUFSIZE];
1255 if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
1256 return;
1257 wpa_printf(MSG_DEBUG, "WPS: PIN needed for UUID-E %s", uuid);
1258 len = os_snprintf(txt, sizeof(txt), "WPS-EVENT-PIN-NEEDED %s " MACSTR
1259 " [%s|%s|%s|%s|%s|%s]",
1260 uuid, MAC2STR(dev->mac_addr), dev->device_name,
1261 dev->manufacturer, dev->model_name,
1262 dev->model_number, dev->serial_number,
1263 wps_dev_type_bin2str(dev->pri_dev_type, devtype,
1264 sizeof(devtype)));
1265 if (len > 0 && len < (int) sizeof(txt))
1266 wpa_printf(MSG_INFO, "%s", txt);
1267}
1268
1269
1270static void wpas_wps_set_sel_reg_cb(void *ctx, int sel_reg, u16 dev_passwd_id,
1271 u16 sel_reg_config_methods)
1272{
1273#ifdef CONFIG_WPS_ER
1274 struct wpa_supplicant *wpa_s = ctx;
1275
1276 if (wpa_s->wps_er == NULL)
1277 return;
1278 wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar - sel_reg=%d "
1279 "dev_password_id=%u sel_reg_config_methods=0x%x",
1280 sel_reg, dev_passwd_id, sel_reg_config_methods);
1281 wps_er_set_sel_reg(wpa_s->wps_er, sel_reg, dev_passwd_id,
1282 sel_reg_config_methods);
1283#endif /* CONFIG_WPS_ER */
1284}
1285
1286
1287static u16 wps_fix_config_methods(u16 config_methods)
1288{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001289 if ((config_methods &
1290 (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY |
1291 WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) {
1292 wpa_printf(MSG_INFO, "WPS: Converting display to "
1293 "virtual_display for WPS 2.0 compliance");
1294 config_methods |= WPS_CONFIG_VIRT_DISPLAY;
1295 }
1296 if ((config_methods &
1297 (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON |
1298 WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) {
1299 wpa_printf(MSG_INFO, "WPS: Converting push_button to "
1300 "virtual_push_button for WPS 2.0 compliance");
1301 config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
1302 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001303
1304 return config_methods;
1305}
1306
1307
1308static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
1309 struct wps_context *wps)
1310{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001311 char buf[50];
1312 const char *src;
1313
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001314 if (is_nil_uuid(wpa_s->conf->uuid)) {
1315 struct wpa_supplicant *first;
1316 first = wpa_s->global->ifaces;
1317 while (first && first->next)
1318 first = first->next;
1319 if (first && first != wpa_s) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001320 if (wps != wpa_s->global->ifaces->wps)
1321 os_memcpy(wps->uuid,
1322 wpa_s->global->ifaces->wps->uuid,
1323 WPS_UUID_LEN);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001324 src = "from the first interface";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001325 } else {
1326 uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001327 src = "based on MAC address";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001328 }
1329 } else {
1330 os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001331 src = "based on configuration";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001332 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001333
1334 uuid_bin2str(wps->uuid, buf, sizeof(buf));
1335 wpa_dbg(wpa_s, MSG_DEBUG, "WPS: UUID %s: %s", src, buf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001336}
1337
1338
Dmitry Shmidt04949592012-07-19 12:16:46 -07001339static void wpas_wps_set_vendor_ext_m1(struct wpa_supplicant *wpa_s,
1340 struct wps_context *wps)
1341{
1342 wpabuf_free(wps->dev.vendor_ext_m1);
1343 wps->dev.vendor_ext_m1 = NULL;
1344
1345 if (wpa_s->conf->wps_vendor_ext_m1) {
1346 wps->dev.vendor_ext_m1 =
1347 wpabuf_dup(wpa_s->conf->wps_vendor_ext_m1);
1348 if (!wps->dev.vendor_ext_m1) {
1349 wpa_printf(MSG_ERROR, "WPS: Cannot "
1350 "allocate memory for vendor_ext_m1");
1351 }
1352 }
1353}
1354
1355
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001356int wpas_wps_init(struct wpa_supplicant *wpa_s)
1357{
1358 struct wps_context *wps;
1359 struct wps_registrar_config rcfg;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001360 struct hostapd_hw_modes *modes;
1361 u16 m;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001362
1363 wps = os_zalloc(sizeof(*wps));
1364 if (wps == NULL)
1365 return -1;
1366
1367 wps->cred_cb = wpa_supplicant_wps_cred;
1368 wps->event_cb = wpa_supplicant_wps_event;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07001369 wps->rf_band_cb = wpa_supplicant_wps_rf_band;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001370 wps->cb_ctx = wpa_s;
1371
1372 wps->dev.device_name = wpa_s->conf->device_name;
1373 wps->dev.manufacturer = wpa_s->conf->manufacturer;
1374 wps->dev.model_name = wpa_s->conf->model_name;
1375 wps->dev.model_number = wpa_s->conf->model_number;
1376 wps->dev.serial_number = wpa_s->conf->serial_number;
1377 wps->config_methods =
1378 wps_config_methods_str2bin(wpa_s->conf->config_methods);
1379 if ((wps->config_methods & (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) ==
1380 (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) {
1381 wpa_printf(MSG_ERROR, "WPS: Both Label and Display config "
1382 "methods are not allowed at the same time");
1383 os_free(wps);
1384 return -1;
1385 }
1386 wps->config_methods = wps_fix_config_methods(wps->config_methods);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001387 wps->dev.config_methods = wps->config_methods;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001388 os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type,
1389 WPS_DEV_TYPE_LEN);
1390
1391 wps->dev.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
1392 os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type,
1393 WPS_DEV_TYPE_LEN * wps->dev.num_sec_dev_types);
1394
Dmitry Shmidt04949592012-07-19 12:16:46 -07001395 wpas_wps_set_vendor_ext_m1(wpa_s, wps);
1396
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001397 wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001398 modes = wpa_s->hw.modes;
1399 if (modes) {
1400 for (m = 0; m < wpa_s->hw.num_modes; m++) {
1401 if (modes[m].mode == HOSTAPD_MODE_IEEE80211B ||
1402 modes[m].mode == HOSTAPD_MODE_IEEE80211G)
1403 wps->dev.rf_bands |= WPS_RF_24GHZ;
1404 else if (modes[m].mode == HOSTAPD_MODE_IEEE80211A)
1405 wps->dev.rf_bands |= WPS_RF_50GHZ;
1406 }
1407 }
1408 if (wps->dev.rf_bands == 0) {
1409 /*
1410 * Default to claiming support for both bands if the driver
1411 * does not provide support for fetching supported bands.
1412 */
1413 wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ;
1414 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001415 os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
1416 wpas_wps_set_uuid(wpa_s, wps);
1417
1418 wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
1419 wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
1420
1421 os_memset(&rcfg, 0, sizeof(rcfg));
1422 rcfg.new_psk_cb = wpas_wps_new_psk_cb;
1423 rcfg.pin_needed_cb = wpas_wps_pin_needed_cb;
1424 rcfg.set_sel_reg_cb = wpas_wps_set_sel_reg_cb;
1425 rcfg.cb_ctx = wpa_s;
1426
1427 wps->registrar = wps_registrar_init(wps, &rcfg);
1428 if (wps->registrar == NULL) {
1429 wpa_printf(MSG_DEBUG, "Failed to initialize WPS Registrar");
1430 os_free(wps);
1431 return -1;
1432 }
1433
1434 wpa_s->wps = wps;
1435
1436 return 0;
1437}
1438
1439
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001440#ifdef CONFIG_WPS_ER
1441static void wpas_wps_nfc_clear(struct wps_context *wps)
1442{
1443 wps->ap_nfc_dev_pw_id = 0;
1444 wpabuf_free(wps->ap_nfc_dh_pubkey);
1445 wps->ap_nfc_dh_pubkey = NULL;
1446 wpabuf_free(wps->ap_nfc_dh_privkey);
1447 wps->ap_nfc_dh_privkey = NULL;
1448 wpabuf_free(wps->ap_nfc_dev_pw);
1449 wps->ap_nfc_dev_pw = NULL;
1450}
1451#endif /* CONFIG_WPS_ER */
1452
1453
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001454void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
1455{
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07001456 wpas_wps_assoc_with_cred_cancel(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001457 eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07001458 eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001459 eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001460 wpas_wps_clear_ap_info(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001461
Dmitry Shmidt684785c2014-05-12 13:34:29 -07001462#ifdef CONFIG_P2P
1463 eloop_cancel_timeout(wpas_p2p_pbc_overlap_cb, wpa_s, NULL);
1464#endif /* CONFIG_P2P */
1465
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001466 if (wpa_s->wps == NULL)
1467 return;
1468
1469#ifdef CONFIG_WPS_ER
1470 wps_er_deinit(wpa_s->wps_er, NULL, NULL);
1471 wpa_s->wps_er = NULL;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001472 wpas_wps_nfc_clear(wpa_s->wps);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001473#endif /* CONFIG_WPS_ER */
1474
1475 wps_registrar_deinit(wpa_s->wps->registrar);
1476 wpabuf_free(wpa_s->wps->dh_pubkey);
1477 wpabuf_free(wpa_s->wps->dh_privkey);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001478 wpabuf_free(wpa_s->wps->dev.vendor_ext_m1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001479 os_free(wpa_s->wps->network_key);
1480 os_free(wpa_s->wps);
1481 wpa_s->wps = NULL;
1482}
1483
1484
1485int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -07001486 struct wpa_ssid *ssid, struct wpa_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001487{
1488 struct wpabuf *wps_ie;
1489
1490 if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
1491 return -1;
1492
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -07001493 wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001494 if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
1495 if (!wps_ie) {
1496 wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
1497 return 0;
1498 }
1499
1500 if (!wps_is_selected_pbc_registrar(wps_ie)) {
1501 wpa_printf(MSG_DEBUG, " skip - WPS AP "
1502 "without active PBC Registrar");
1503 wpabuf_free(wps_ie);
1504 return 0;
1505 }
1506
1507 /* TODO: overlap detection */
1508 wpa_printf(MSG_DEBUG, " selected based on WPS IE "
1509 "(Active PBC)");
1510 wpabuf_free(wps_ie);
1511 return 1;
1512 }
1513
1514 if (eap_is_wps_pin_enrollee(&ssid->eap)) {
1515 if (!wps_ie) {
1516 wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
1517 return 0;
1518 }
1519
1520 /*
1521 * Start with WPS APs that advertise our address as an
1522 * authorized MAC (v2.0) or active PIN Registrar (v1.0) and
1523 * allow any WPS AP after couple of scans since some APs do not
1524 * set Selected Registrar attribute properly when using
1525 * external Registrar.
1526 */
1527 if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
1528 if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) {
1529 wpa_printf(MSG_DEBUG, " skip - WPS AP "
1530 "without active PIN Registrar");
1531 wpabuf_free(wps_ie);
1532 return 0;
1533 }
1534 wpa_printf(MSG_DEBUG, " selected based on WPS IE");
1535 } else {
1536 wpa_printf(MSG_DEBUG, " selected based on WPS IE "
1537 "(Authorized MAC or Active PIN)");
1538 }
1539 wpabuf_free(wps_ie);
1540 return 1;
1541 }
1542
1543 if (wps_ie) {
1544 wpa_printf(MSG_DEBUG, " selected based on WPS IE");
1545 wpabuf_free(wps_ie);
1546 return 1;
1547 }
1548
1549 return -1;
1550}
1551
1552
1553int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
1554 struct wpa_ssid *ssid,
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -07001555 struct wpa_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001556{
1557 struct wpabuf *wps_ie = NULL;
1558 int ret = 0;
1559
1560 if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -07001561 wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001562 if (wps_ie && wps_is_selected_pbc_registrar(wps_ie)) {
1563 /* allow wildcard SSID for WPS PBC */
1564 ret = 1;
1565 }
1566 } else if (eap_is_wps_pin_enrollee(&ssid->eap)) {
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -07001567 wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001568 if (wps_ie &&
1569 (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1) ||
1570 wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) {
1571 /* allow wildcard SSID for WPS PIN */
1572 ret = 1;
1573 }
1574 }
1575
1576 if (!ret && ssid->bssid_set &&
1577 os_memcmp(ssid->bssid, bss->bssid, ETH_ALEN) == 0) {
1578 /* allow wildcard SSID due to hardcoded BSSID match */
1579 ret = 1;
1580 }
1581
1582#ifdef CONFIG_WPS_STRICT
1583 if (wps_ie) {
1584 if (wps_validate_beacon_probe_resp(wps_ie, bss->beacon_ie_len >
1585 0, bss->bssid) < 0)
1586 ret = 0;
1587 if (bss->beacon_ie_len) {
1588 struct wpabuf *bcn_wps;
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -07001589 bcn_wps = wpa_bss_get_vendor_ie_multi_beacon(
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001590 bss, WPS_IE_VENDOR_TYPE);
1591 if (bcn_wps == NULL) {
1592 wpa_printf(MSG_DEBUG, "WPS: Mandatory WPS IE "
1593 "missing from AP Beacon");
1594 ret = 0;
1595 } else {
1596 if (wps_validate_beacon(wps_ie) < 0)
1597 ret = 0;
1598 wpabuf_free(bcn_wps);
1599 }
1600 }
1601 }
1602#endif /* CONFIG_WPS_STRICT */
1603
1604 wpabuf_free(wps_ie);
1605
1606 return ret;
1607}
1608
1609
1610int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
1611 struct wpa_bss *selected, struct wpa_ssid *ssid)
1612{
1613 const u8 *sel_uuid, *uuid;
1614 struct wpabuf *wps_ie;
1615 int ret = 0;
1616 struct wpa_bss *bss;
1617
1618 if (!eap_is_wps_pbc_enrollee(&ssid->eap))
1619 return 0;
1620
1621 wpa_printf(MSG_DEBUG, "WPS: Check whether PBC session overlap is "
1622 "present in scan results; selected BSSID " MACSTR,
1623 MAC2STR(selected->bssid));
1624
1625 /* Make sure that only one AP is in active PBC mode */
1626 wps_ie = wpa_bss_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE);
1627 if (wps_ie) {
1628 sel_uuid = wps_get_uuid_e(wps_ie);
1629 wpa_hexdump(MSG_DEBUG, "WPS: UUID of the selected BSS",
1630 sel_uuid, UUID_LEN);
1631 } else {
1632 wpa_printf(MSG_DEBUG, "WPS: Selected BSS does not include "
1633 "WPS IE?!");
1634 sel_uuid = NULL;
1635 }
1636
1637 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
1638 struct wpabuf *ie;
1639 if (bss == selected)
1640 continue;
1641 ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
1642 if (!ie)
1643 continue;
1644 if (!wps_is_selected_pbc_registrar(ie)) {
1645 wpabuf_free(ie);
1646 continue;
1647 }
1648 wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: "
1649 MACSTR, MAC2STR(bss->bssid));
1650 uuid = wps_get_uuid_e(ie);
1651 wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
1652 uuid, UUID_LEN);
1653 if (sel_uuid == NULL || uuid == NULL ||
1654 os_memcmp(sel_uuid, uuid, UUID_LEN) != 0) {
1655 ret = 1; /* PBC overlap */
1656 wpa_msg(wpa_s, MSG_INFO, "WPS: PBC overlap detected: "
1657 MACSTR " and " MACSTR,
1658 MAC2STR(selected->bssid),
1659 MAC2STR(bss->bssid));
1660 wpabuf_free(ie);
1661 break;
1662 }
1663
1664 /* TODO: verify that this is reasonable dual-band situation */
1665
1666 wpabuf_free(ie);
1667 }
1668
1669 wpabuf_free(wps_ie);
1670
1671 return ret;
1672}
1673
1674
1675void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s)
1676{
1677 struct wpa_bss *bss;
1678 unsigned int pbc = 0, auth = 0, pin = 0, wps = 0;
1679
1680 if (wpa_s->disconnected || wpa_s->wpa_state >= WPA_ASSOCIATED)
1681 return;
1682
1683 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
1684 struct wpabuf *ie;
1685 ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
1686 if (!ie)
1687 continue;
1688 if (wps_is_selected_pbc_registrar(ie))
1689 pbc++;
1690 else if (wps_is_addr_authorized(ie, wpa_s->own_addr, 0))
1691 auth++;
1692 else if (wps_is_selected_pin_registrar(ie))
1693 pin++;
1694 else
1695 wps++;
1696 wpabuf_free(ie);
1697 }
1698
1699 if (pbc)
1700 wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PBC);
1701 else if (auth)
1702 wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_AUTH);
1703 else if (pin)
1704 wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PIN);
1705 else if (wps)
1706 wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE);
1707}
1708
1709
1710int wpas_wps_searching(struct wpa_supplicant *wpa_s)
1711{
1712 struct wpa_ssid *ssid;
1713
1714 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1715 if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && !ssid->disabled)
1716 return 1;
1717 }
1718
1719 return 0;
1720}
1721
1722
1723int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
1724 char *end)
1725{
1726 struct wpabuf *wps_ie;
1727 int ret;
1728
1729 wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, WPS_DEV_OUI_WFA);
1730 if (wps_ie == NULL)
1731 return 0;
1732
1733 ret = wps_attr_text(wps_ie, buf, end);
1734 wpabuf_free(wps_ie);
1735 return ret;
1736}
1737
1738
1739int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter)
1740{
1741#ifdef CONFIG_WPS_ER
1742 if (wpa_s->wps_er) {
1743 wps_er_refresh(wpa_s->wps_er);
1744 return 0;
1745 }
1746 wpa_s->wps_er = wps_er_init(wpa_s->wps, wpa_s->ifname, filter);
1747 if (wpa_s->wps_er == NULL)
1748 return -1;
1749 return 0;
1750#else /* CONFIG_WPS_ER */
1751 return 0;
1752#endif /* CONFIG_WPS_ER */
1753}
1754
1755
1756int wpas_wps_er_stop(struct wpa_supplicant *wpa_s)
1757{
1758#ifdef CONFIG_WPS_ER
1759 wps_er_deinit(wpa_s->wps_er, NULL, NULL);
1760 wpa_s->wps_er = NULL;
1761#endif /* CONFIG_WPS_ER */
1762 return 0;
1763}
1764
1765
1766#ifdef CONFIG_WPS_ER
1767int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr,
1768 const char *uuid, const char *pin)
1769{
1770 u8 u[UUID_LEN];
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001771 const u8 *use_uuid = NULL;
1772 u8 addr_buf[ETH_ALEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001773
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001774 if (os_strcmp(uuid, "any") == 0) {
1775 } else if (uuid_str2bin(uuid, u) == 0) {
1776 use_uuid = u;
1777 } else if (hwaddr_aton(uuid, addr_buf) == 0) {
1778 use_uuid = wps_er_get_sta_uuid(wpa_s->wps_er, addr_buf);
1779 if (use_uuid == NULL)
1780 return -1;
1781 } else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001782 return -1;
1783 return wps_registrar_add_pin(wpa_s->wps->registrar, addr,
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001784 use_uuid,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001785 (const u8 *) pin, os_strlen(pin), 300);
1786}
1787
1788
1789int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid)
1790{
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001791 u8 u[UUID_LEN], *use_uuid = NULL;
1792 u8 addr[ETH_ALEN], *use_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001793
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001794 if (uuid_str2bin(uuid, u) == 0)
1795 use_uuid = u;
1796 else if (hwaddr_aton(uuid, addr) == 0)
1797 use_addr = addr;
1798 else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001799 return -1;
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001800 return wps_er_pbc(wpa_s->wps_er, use_uuid, use_addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001801}
1802
1803
1804int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
1805 const char *pin)
1806{
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001807 u8 u[UUID_LEN], *use_uuid = NULL;
1808 u8 addr[ETH_ALEN], *use_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001809
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001810 if (uuid_str2bin(uuid, u) == 0)
1811 use_uuid = u;
1812 else if (hwaddr_aton(uuid, addr) == 0)
1813 use_addr = addr;
1814 else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001815 return -1;
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001816
1817 return wps_er_learn(wpa_s->wps_er, use_uuid, use_addr, (const u8 *) pin,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001818 os_strlen(pin));
1819}
1820
1821
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001822static int wpas_wps_network_to_cred(struct wpa_ssid *ssid,
1823 struct wps_credential *cred)
1824{
1825 os_memset(cred, 0, sizeof(*cred));
1826 if (ssid->ssid_len > 32)
1827 return -1;
1828 os_memcpy(cred->ssid, ssid->ssid, ssid->ssid_len);
1829 cred->ssid_len = ssid->ssid_len;
1830 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
1831 cred->auth_type = (ssid->proto & WPA_PROTO_RSN) ?
1832 WPS_AUTH_WPA2PSK : WPS_AUTH_WPAPSK;
1833 if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
1834 cred->encr_type = WPS_ENCR_AES;
1835 else
1836 cred->encr_type = WPS_ENCR_TKIP;
1837 if (ssid->passphrase) {
1838 cred->key_len = os_strlen(ssid->passphrase);
1839 if (cred->key_len >= 64)
1840 return -1;
1841 os_memcpy(cred->key, ssid->passphrase, cred->key_len);
1842 } else if (ssid->psk_set) {
1843 cred->key_len = 32;
1844 os_memcpy(cred->key, ssid->psk, 32);
1845 } else
1846 return -1;
1847 } else {
1848 cred->auth_type = WPS_AUTH_OPEN;
1849 cred->encr_type = WPS_ENCR_NONE;
1850 }
1851
1852 return 0;
1853}
1854
1855
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001856int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
1857 int id)
1858{
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001859 u8 u[UUID_LEN], *use_uuid = NULL;
1860 u8 addr[ETH_ALEN], *use_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001861 struct wpa_ssid *ssid;
1862 struct wps_credential cred;
1863
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001864 if (uuid_str2bin(uuid, u) == 0)
1865 use_uuid = u;
1866 else if (hwaddr_aton(uuid, addr) == 0)
1867 use_addr = addr;
1868 else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001869 return -1;
1870 ssid = wpa_config_get_network(wpa_s->conf, id);
1871 if (ssid == NULL || ssid->ssid == NULL)
1872 return -1;
1873
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001874 if (wpas_wps_network_to_cred(ssid, &cred) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001875 return -1;
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001876 return wps_er_set_config(wpa_s->wps_er, use_uuid, use_addr, &cred);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001877}
1878
1879
1880int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
1881 const char *pin, struct wps_new_ap_settings *settings)
1882{
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001883 u8 u[UUID_LEN], *use_uuid = NULL;
1884 u8 addr[ETH_ALEN], *use_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001885 struct wps_credential cred;
1886 size_t len;
1887
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001888 if (uuid_str2bin(uuid, u) == 0)
1889 use_uuid = u;
1890 else if (hwaddr_aton(uuid, addr) == 0)
1891 use_addr = addr;
1892 else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001893 return -1;
1894 if (settings->ssid_hex == NULL || settings->auth == NULL ||
1895 settings->encr == NULL || settings->key_hex == NULL)
1896 return -1;
1897
1898 os_memset(&cred, 0, sizeof(cred));
1899 len = os_strlen(settings->ssid_hex);
1900 if ((len & 1) || len > 2 * sizeof(cred.ssid) ||
1901 hexstr2bin(settings->ssid_hex, cred.ssid, len / 2))
1902 return -1;
1903 cred.ssid_len = len / 2;
1904
1905 len = os_strlen(settings->key_hex);
1906 if ((len & 1) || len > 2 * sizeof(cred.key) ||
1907 hexstr2bin(settings->key_hex, cred.key, len / 2))
1908 return -1;
1909 cred.key_len = len / 2;
1910
1911 if (os_strcmp(settings->auth, "OPEN") == 0)
1912 cred.auth_type = WPS_AUTH_OPEN;
1913 else if (os_strcmp(settings->auth, "WPAPSK") == 0)
1914 cred.auth_type = WPS_AUTH_WPAPSK;
1915 else if (os_strcmp(settings->auth, "WPA2PSK") == 0)
1916 cred.auth_type = WPS_AUTH_WPA2PSK;
1917 else
1918 return -1;
1919
1920 if (os_strcmp(settings->encr, "NONE") == 0)
1921 cred.encr_type = WPS_ENCR_NONE;
Dmitry Shmidt21de2142014-04-08 10:50:52 -07001922#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001923 else if (os_strcmp(settings->encr, "WEP") == 0)
1924 cred.encr_type = WPS_ENCR_WEP;
Dmitry Shmidt21de2142014-04-08 10:50:52 -07001925#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001926 else if (os_strcmp(settings->encr, "TKIP") == 0)
1927 cred.encr_type = WPS_ENCR_TKIP;
1928 else if (os_strcmp(settings->encr, "CCMP") == 0)
1929 cred.encr_type = WPS_ENCR_AES;
1930 else
1931 return -1;
1932
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001933 return wps_er_config(wpa_s->wps_er, use_uuid, use_addr,
1934 (const u8 *) pin, os_strlen(pin), &cred);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001935}
1936
1937
Dmitry Shmidt04949592012-07-19 12:16:46 -07001938#ifdef CONFIG_WPS_NFC
1939struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
1940 int ndef, const char *uuid)
1941{
1942 struct wpabuf *ret;
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001943 u8 u[UUID_LEN], *use_uuid = NULL;
1944 u8 addr[ETH_ALEN], *use_addr = NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001945
1946 if (!wpa_s->wps_er)
1947 return NULL;
1948
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001949 if (uuid_str2bin(uuid, u) == 0)
1950 use_uuid = u;
1951 else if (hwaddr_aton(uuid, addr) == 0)
1952 use_addr = addr;
1953 else
Dmitry Shmidt04949592012-07-19 12:16:46 -07001954 return NULL;
1955
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001956 ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001957 if (ndef && ret) {
1958 struct wpabuf *tmp;
1959 tmp = ndef_build_wifi(ret);
1960 wpabuf_free(ret);
1961 if (tmp == NULL)
1962 return NULL;
1963 ret = tmp;
1964 }
1965
1966 return ret;
1967}
1968#endif /* CONFIG_WPS_NFC */
1969
1970
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001971static int callbacks_pending = 0;
1972
1973static void wpas_wps_terminate_cb(void *ctx)
1974{
1975 wpa_printf(MSG_DEBUG, "WPS ER: Terminated");
1976 if (--callbacks_pending <= 0)
1977 eloop_terminate();
1978}
1979#endif /* CONFIG_WPS_ER */
1980
1981
1982int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s)
1983{
1984#ifdef CONFIG_WPS_ER
1985 if (wpa_s->wps_er) {
1986 callbacks_pending++;
1987 wps_er_deinit(wpa_s->wps_er, wpas_wps_terminate_cb, wpa_s);
1988 wpa_s->wps_er = NULL;
1989 return 1;
1990 }
1991#endif /* CONFIG_WPS_ER */
1992 return 0;
1993}
1994
1995
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001996void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
1997{
1998 struct wps_context *wps = wpa_s->wps;
1999
2000 if (wps == NULL)
2001 return;
2002
2003 if (wpa_s->conf->changed_parameters & CFG_CHANGED_CONFIG_METHODS) {
2004 wps->config_methods = wps_config_methods_str2bin(
2005 wpa_s->conf->config_methods);
2006 if ((wps->config_methods &
2007 (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) ==
2008 (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) {
2009 wpa_printf(MSG_ERROR, "WPS: Both Label and Display "
2010 "config methods are not allowed at the "
2011 "same time");
2012 wps->config_methods &= ~WPS_CONFIG_LABEL;
2013 }
2014 }
2015 wps->config_methods = wps_fix_config_methods(wps->config_methods);
jim1_linff2bda62012-06-26 11:04:38 +08002016 wps->dev.config_methods = wps->config_methods;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002017
2018 if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE)
2019 os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type,
2020 WPS_DEV_TYPE_LEN);
2021
2022 if (wpa_s->conf->changed_parameters & CFG_CHANGED_SEC_DEVICE_TYPE) {
2023 wps->dev.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
2024 os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type,
2025 wps->dev.num_sec_dev_types * WPS_DEV_TYPE_LEN);
2026 }
2027
Dmitry Shmidt04949592012-07-19 12:16:46 -07002028 if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION)
2029 wpas_wps_set_vendor_ext_m1(wpa_s, wps);
2030
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002031 if (wpa_s->conf->changed_parameters & CFG_CHANGED_OS_VERSION)
2032 wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
2033
2034 if (wpa_s->conf->changed_parameters & CFG_CHANGED_UUID)
2035 wpas_wps_set_uuid(wpa_s, wps);
2036
2037 if (wpa_s->conf->changed_parameters &
2038 (CFG_CHANGED_DEVICE_NAME | CFG_CHANGED_WPS_STRING)) {
2039 /* Update pointers to make sure they refer current values */
2040 wps->dev.device_name = wpa_s->conf->device_name;
2041 wps->dev.manufacturer = wpa_s->conf->manufacturer;
2042 wps->dev.model_name = wpa_s->conf->model_name;
2043 wps->dev.model_number = wpa_s->conf->model_number;
2044 wps->dev.serial_number = wpa_s->conf->serial_number;
2045 }
2046}
Dmitry Shmidt04949592012-07-19 12:16:46 -07002047
2048
2049#ifdef CONFIG_WPS_NFC
2050
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002051#ifdef CONFIG_WPS_ER
2052static struct wpabuf *
2053wpas_wps_network_config_token(struct wpa_supplicant *wpa_s, int ndef,
2054 struct wpa_ssid *ssid)
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002055{
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002056 struct wpabuf *ret;
2057 struct wps_credential cred;
2058
2059 if (wpas_wps_network_to_cred(ssid, &cred) < 0)
2060 return NULL;
2061
2062 ret = wps_er_config_token_from_cred(wpa_s->wps, &cred);
2063
2064 if (ndef && ret) {
2065 struct wpabuf *tmp;
2066 tmp = ndef_build_wifi(ret);
2067 wpabuf_free(ret);
2068 if (tmp == NULL)
2069 return NULL;
2070 ret = tmp;
2071 }
2072
2073 return ret;
2074}
2075#endif /* CONFIG_WPS_ER */
2076
2077
2078struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
2079 int ndef, const char *id_str)
2080{
2081#ifdef CONFIG_WPS_ER
2082 if (id_str) {
2083 int id;
2084 char *end = NULL;
2085 struct wpa_ssid *ssid;
2086
2087 id = strtol(id_str, &end, 10);
2088 if (end && *end)
2089 return NULL;
2090
2091 ssid = wpa_config_get_network(wpa_s->conf, id);
2092 if (ssid == NULL)
2093 return NULL;
2094 return wpas_wps_network_config_token(wpa_s, ndef, ssid);
2095 }
2096#endif /* CONFIG_WPS_ER */
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002097#ifdef CONFIG_AP
2098 if (wpa_s->ap_iface)
2099 return wpas_ap_wps_nfc_config_token(wpa_s, ndef);
2100#endif /* CONFIG_AP */
2101 return NULL;
2102}
2103
2104
Dmitry Shmidt04949592012-07-19 12:16:46 -07002105struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef)
2106{
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002107 if (wpa_s->conf->wps_nfc_pw_from_config) {
2108 return wps_nfc_token_build(ndef,
2109 wpa_s->conf->wps_nfc_dev_pw_id,
2110 wpa_s->conf->wps_nfc_dh_pubkey,
2111 wpa_s->conf->wps_nfc_dev_pw);
2112 }
2113
Dmitry Shmidt04949592012-07-19 12:16:46 -07002114 return wps_nfc_token_gen(ndef, &wpa_s->conf->wps_nfc_dev_pw_id,
2115 &wpa_s->conf->wps_nfc_dh_pubkey,
2116 &wpa_s->conf->wps_nfc_dh_privkey,
2117 &wpa_s->conf->wps_nfc_dev_pw);
2118}
2119
2120
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002121int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *go_dev_addr,
2122 const u8 *bssid,
2123 const struct wpabuf *dev_pw, u16 dev_pw_id,
2124 int p2p_group, const u8 *peer_pubkey_hash,
2125 const u8 *ssid, size_t ssid_len, int freq)
Dmitry Shmidt04949592012-07-19 12:16:46 -07002126{
2127 struct wps_context *wps = wpa_s->wps;
2128 char pw[32 * 2 + 1];
2129
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002130 if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && dev_pw == NULL) {
2131 dev_pw = wpa_s->conf->wps_nfc_dev_pw;
2132 dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id;
2133 }
2134
Dmitry Shmidt04949592012-07-19 12:16:46 -07002135 if (wpa_s->conf->wps_nfc_dh_pubkey == NULL ||
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002136 wpa_s->conf->wps_nfc_dh_privkey == NULL) {
2137 wpa_printf(MSG_DEBUG, "WPS: Missing DH params - "
2138 "cannot start NFC-triggered connection");
Dmitry Shmidt04949592012-07-19 12:16:46 -07002139 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002140 }
2141
2142 if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && dev_pw == NULL) {
2143 wpa_printf(MSG_DEBUG, "WPS: Missing Device Password (id=%u) - "
2144 "cannot start NFC-triggered connection", dev_pw_id);
2145 return -1;
2146 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002147
2148 dh5_free(wps->dh_ctx);
2149 wpabuf_free(wps->dh_pubkey);
2150 wpabuf_free(wps->dh_privkey);
2151 wps->dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
2152 wps->dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
2153 if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
2154 wps->dh_ctx = NULL;
2155 wpabuf_free(wps->dh_pubkey);
2156 wps->dh_pubkey = NULL;
2157 wpabuf_free(wps->dh_privkey);
2158 wps->dh_privkey = NULL;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002159 wpa_printf(MSG_DEBUG, "WPS: Failed to get DH priv/pub key");
Dmitry Shmidt04949592012-07-19 12:16:46 -07002160 return -1;
2161 }
2162 wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002163 if (wps->dh_ctx == NULL) {
2164 wpabuf_free(wps->dh_pubkey);
2165 wps->dh_pubkey = NULL;
2166 wpabuf_free(wps->dh_privkey);
2167 wps->dh_privkey = NULL;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002168 wpa_printf(MSG_DEBUG, "WPS: Failed to initialize DH context");
Dmitry Shmidt04949592012-07-19 12:16:46 -07002169 return -1;
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002170 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002171
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002172 if (dev_pw) {
2173 wpa_snprintf_hex_uppercase(pw, sizeof(pw),
2174 wpabuf_head(dev_pw),
2175 wpabuf_len(dev_pw));
2176 }
2177 return wpas_wps_start_dev_pw(wpa_s, go_dev_addr, bssid,
2178 dev_pw ? pw : NULL,
2179 p2p_group, dev_pw_id, peer_pubkey_hash,
2180 ssid, ssid_len, freq);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002181}
2182
2183
2184static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
2185 struct wps_parse_attr *attr)
2186{
Dmitry Shmidt44c95782013-05-17 09:51:35 -07002187 /*
2188 * Disable existing networks temporarily to allow the newly learned
2189 * credential to be preferred. Enable the temporarily disabled networks
2190 * after 10 seconds.
2191 */
2192 wpas_wps_temp_disable(wpa_s, NULL);
2193 eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
2194 NULL);
2195
Dmitry Shmidt04949592012-07-19 12:16:46 -07002196 if (wps_oob_use_cred(wpa_s->wps, attr) < 0)
2197 return -1;
2198
2199 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
2200 return 0;
2201
Dmitry Shmidt3c479372014-02-04 10:50:36 -08002202 if (attr->ap_channel) {
2203 u16 chan = WPA_GET_BE16(attr->ap_channel);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002204 int freq = 0;
2205
2206 if (chan >= 1 && chan <= 13)
2207 freq = 2407 + 5 * chan;
2208 else if (chan == 14)
2209 freq = 2484;
2210 else if (chan >= 30)
2211 freq = 5000 + 5 * chan;
2212
2213 if (freq) {
Dmitry Shmidt3c479372014-02-04 10:50:36 -08002214 wpa_printf(MSG_DEBUG, "WPS: Credential container indicated AP channel %u -> %u MHz",
2215 chan, freq);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002216 wpa_s->after_wps = 5;
2217 wpa_s->wps_freq = freq;
2218 }
2219 }
Dmitry Shmidt3c479372014-02-04 10:50:36 -08002220
2221 wpa_printf(MSG_DEBUG, "WPS: Request reconnection with new network "
2222 "based on the received credential added");
2223 wpa_s->normal_scans = 0;
2224 wpa_supplicant_reinit_autoscan(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002225 wpa_s->disconnected = 0;
2226 wpa_s->reassociate = 1;
Dmitry Shmidt96571392013-10-14 12:54:46 -07002227
2228 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002229 wpa_supplicant_req_scan(wpa_s, 0, 0);
2230
2231 return 0;
2232}
2233
2234
Dmitry Shmidtaa532512012-09-24 10:35:31 -07002235#ifdef CONFIG_WPS_ER
Dmitry Shmidt04949592012-07-19 12:16:46 -07002236static int wpas_wps_add_nfc_password_token(struct wpa_supplicant *wpa_s,
2237 struct wps_parse_attr *attr)
2238{
2239 return wps_registrar_add_nfc_password_token(
2240 wpa_s->wps->registrar, attr->oob_dev_password,
2241 attr->oob_dev_password_len);
2242}
Dmitry Shmidtaa532512012-09-24 10:35:31 -07002243#endif /* CONFIG_WPS_ER */
Dmitry Shmidt04949592012-07-19 12:16:46 -07002244
2245
2246static int wpas_wps_nfc_tag_process(struct wpa_supplicant *wpa_s,
2247 const struct wpabuf *wps)
2248{
2249 struct wps_parse_attr attr;
2250
2251 wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
2252
2253 if (wps_parse_msg(wps, &attr)) {
2254 wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
2255 return -1;
2256 }
2257
2258 if (attr.num_cred)
2259 return wpas_wps_use_cred(wpa_s, &attr);
2260
2261#ifdef CONFIG_WPS_ER
2262 if (attr.oob_dev_password)
2263 return wpas_wps_add_nfc_password_token(wpa_s, &attr);
2264#endif /* CONFIG_WPS_ER */
2265
2266 wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
2267 return -1;
2268}
2269
2270
2271int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002272 const struct wpabuf *data, int forced_freq)
Dmitry Shmidt04949592012-07-19 12:16:46 -07002273{
2274 const struct wpabuf *wps = data;
2275 struct wpabuf *tmp = NULL;
2276 int ret;
2277
2278 if (wpabuf_len(data) < 4)
2279 return -1;
2280
2281 if (*wpabuf_head_u8(data) != 0x10) {
2282 /* Assume this contains full NDEF record */
2283 tmp = ndef_parse_wifi(data);
2284 if (tmp == NULL) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002285#ifdef CONFIG_P2P
2286 tmp = ndef_parse_p2p(data);
2287 if (tmp) {
2288 ret = wpas_p2p_nfc_tag_process(wpa_s, tmp,
2289 forced_freq);
2290 wpabuf_free(tmp);
2291 return ret;
2292 }
2293#endif /* CONFIG_P2P */
Dmitry Shmidt04949592012-07-19 12:16:46 -07002294 wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
2295 return -1;
2296 }
2297 wps = tmp;
2298 }
2299
2300 ret = wpas_wps_nfc_tag_process(wpa_s, wps);
2301 wpabuf_free(tmp);
2302 return ret;
2303}
2304
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002305
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002306struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s,
2307 int ndef)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002308{
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002309 struct wpabuf *ret;
2310
2311 if (wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
2312 wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
2313 &wpa_s->conf->wps_nfc_dh_privkey) < 0)
2314 return NULL;
2315
2316 ret = wps_build_nfc_handover_req(wpa_s->wps,
2317 wpa_s->conf->wps_nfc_dh_pubkey);
2318
2319 if (ndef && ret) {
2320 struct wpabuf *tmp;
2321 tmp = ndef_build_wifi(ret);
2322 wpabuf_free(ret);
2323 if (tmp == NULL)
2324 return NULL;
2325 ret = tmp;
2326 }
2327
2328 return ret;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002329}
2330
2331
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002332#ifdef CONFIG_WPS_NFC
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002333
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002334static struct wpabuf *
2335wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef,
2336 const char *uuid)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002337{
Dmitry Shmidt700a1372013-03-15 14:14:44 -07002338#ifdef CONFIG_WPS_ER
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002339 struct wpabuf *ret;
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002340 u8 u[UUID_LEN], *use_uuid = NULL;
2341 u8 addr[ETH_ALEN], *use_addr = NULL;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002342 struct wps_context *wps = wpa_s->wps;
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002343
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002344 if (wps == NULL)
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002345 return NULL;
2346
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07002347 if (uuid == NULL)
2348 return NULL;
2349 if (uuid_str2bin(uuid, u) == 0)
2350 use_uuid = u;
2351 else if (hwaddr_aton(uuid, addr) == 0)
2352 use_addr = addr;
2353 else
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002354 return NULL;
2355
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002356 if (wpa_s->conf->wps_nfc_dh_pubkey == NULL) {
2357 if (wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
2358 &wpa_s->conf->wps_nfc_dh_privkey) < 0)
2359 return NULL;
2360 }
2361
2362 wpas_wps_nfc_clear(wps);
2363 wps->ap_nfc_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
2364 wps->ap_nfc_dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
2365 wps->ap_nfc_dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
2366 if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey) {
2367 wpas_wps_nfc_clear(wps);
2368 return NULL;
2369 }
2370
2371 ret = wps_er_nfc_handover_sel(wpa_s->wps_er, wpa_s->wps, use_uuid,
2372 use_addr, wpa_s->conf->wps_nfc_dh_pubkey);
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002373 if (ndef && ret) {
2374 struct wpabuf *tmp;
2375 tmp = ndef_build_wifi(ret);
2376 wpabuf_free(ret);
2377 if (tmp == NULL)
2378 return NULL;
2379 ret = tmp;
2380 }
2381
2382 return ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07002383#else /* CONFIG_WPS_ER */
2384 return NULL;
2385#endif /* CONFIG_WPS_ER */
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002386}
2387#endif /* CONFIG_WPS_NFC */
2388
2389
2390struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
2391 int ndef, int cr, const char *uuid)
2392{
2393 struct wpabuf *ret;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002394 if (!cr)
2395 return NULL;
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08002396 ret = wpas_ap_wps_nfc_handover_sel(wpa_s, ndef);
2397 if (ret)
2398 return ret;
2399 return wpas_wps_er_nfc_handover_sel(wpa_s, ndef, uuid);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002400}
2401
2402
Dmitry Shmidt21de2142014-04-08 10:50:52 -07002403static int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
2404 const struct wpabuf *data)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002405{
2406 struct wpabuf *wps;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002407 int ret = -1;
2408 u16 wsc_len;
2409 const u8 *pos;
2410 struct wpabuf msg;
2411 struct wps_parse_attr attr;
2412 u16 dev_pw_id;
2413 const u8 *bssid = NULL;
2414 int freq = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002415
2416 wps = ndef_parse_wifi(data);
2417 if (wps == NULL)
2418 return -1;
2419 wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
2420 "payload from NFC connection handover");
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002421 wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
2422 if (wpabuf_len(wps) < 2) {
2423 wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Select "
2424 "Message");
2425 goto out;
2426 }
2427 pos = wpabuf_head(wps);
2428 wsc_len = WPA_GET_BE16(pos);
2429 if (wsc_len > wpabuf_len(wps) - 2) {
2430 wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
2431 "in Wi-Fi Handover Select Message", wsc_len);
2432 goto out;
2433 }
2434 pos += 2;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002435
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002436 wpa_hexdump(MSG_DEBUG,
2437 "WPS: WSC attributes in Wi-Fi Handover Select Message",
2438 pos, wsc_len);
2439 if (wsc_len < wpabuf_len(wps) - 2) {
2440 wpa_hexdump(MSG_DEBUG,
2441 "WPS: Ignore extra data after WSC attributes",
2442 pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
2443 }
2444
2445 wpabuf_set(&msg, pos, wsc_len);
2446 ret = wps_parse_msg(&msg, &attr);
2447 if (ret < 0) {
2448 wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
2449 "Wi-Fi Handover Select Message");
2450 goto out;
2451 }
2452
2453 if (attr.oob_dev_password == NULL ||
2454 attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
2455 wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
2456 "included in Wi-Fi Handover Select Message");
2457 ret = -1;
2458 goto out;
2459 }
2460
2461 if (attr.ssid == NULL) {
2462 wpa_printf(MSG_DEBUG, "WPS: No SSID included in Wi-Fi Handover "
2463 "Select Message");
2464 ret = -1;
2465 goto out;
2466 }
2467
2468 wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", attr.ssid, attr.ssid_len);
2469
2470 if (attr.mac_addr) {
2471 bssid = attr.mac_addr;
2472 wpa_printf(MSG_DEBUG, "WPS: MAC Address (BSSID): " MACSTR,
2473 MAC2STR(bssid));
2474 }
2475
2476 if (attr.rf_bands)
2477 wpa_printf(MSG_DEBUG, "WPS: RF Bands: %d", *attr.rf_bands);
2478
2479 if (attr.ap_channel) {
2480 u16 chan = WPA_GET_BE16(attr.ap_channel);
2481
2482 wpa_printf(MSG_DEBUG, "WPS: AP Channel: %d", chan);
2483
2484 if (chan >= 1 && chan <= 13 &&
2485 (attr.rf_bands == NULL || *attr.rf_bands & WPS_RF_24GHZ))
2486 freq = 2407 + 5 * chan;
2487 else if (chan == 14 &&
2488 (attr.rf_bands == NULL ||
2489 *attr.rf_bands & WPS_RF_24GHZ))
2490 freq = 2484;
2491 else if (chan >= 30 &&
2492 (attr.rf_bands == NULL ||
2493 *attr.rf_bands & WPS_RF_50GHZ))
2494 freq = 5000 + 5 * chan;
2495
2496 if (freq) {
2497 wpa_printf(MSG_DEBUG,
2498 "WPS: AP indicated channel %u -> %u MHz",
2499 chan, freq);
2500 }
2501 }
2502
2503 wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
2504 attr.oob_dev_password, attr.oob_dev_password_len);
2505 dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
2506 WPS_OOB_PUBKEY_HASH_LEN);
2507 if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
2508 wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
2509 "%u in Wi-Fi Handover Select Message", dev_pw_id);
2510 ret = -1;
2511 goto out;
2512 }
2513 wpa_hexdump(MSG_DEBUG, "WPS: AP Public Key hash",
2514 attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
2515
2516 ret = wpas_wps_start_nfc(wpa_s, NULL, bssid, NULL, dev_pw_id, 0,
2517 attr.oob_dev_password,
2518 attr.ssid, attr.ssid_len, freq);
2519
2520out:
2521 wpabuf_free(wps);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002522 return ret;
2523}
2524
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002525
2526int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
2527 const struct wpabuf *req,
2528 const struct wpabuf *sel)
2529{
2530 wpa_printf(MSG_DEBUG, "NFC: WPS connection handover reported");
2531 wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in request", req);
2532 wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in select", sel);
2533 return wpas_wps_nfc_rx_handover_sel(wpa_s, sel);
2534}
2535
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002536
2537int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
2538 const struct wpabuf *req,
2539 const struct wpabuf *sel)
2540{
2541 struct wpabuf *wps;
2542 int ret = -1;
2543 u16 wsc_len;
2544 const u8 *pos;
2545 struct wpabuf msg;
2546 struct wps_parse_attr attr;
2547 u16 dev_pw_id;
2548
2549 /*
2550 * Enrollee/station is always initiator of the NFC connection handover,
2551 * so use the request message here to find Enrollee public key hash.
2552 */
2553 wps = ndef_parse_wifi(req);
2554 if (wps == NULL)
2555 return -1;
2556 wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
2557 "payload from NFC connection handover");
2558 wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
2559 if (wpabuf_len(wps) < 2) {
2560 wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Request "
2561 "Message");
2562 goto out;
2563 }
2564 pos = wpabuf_head(wps);
2565 wsc_len = WPA_GET_BE16(pos);
2566 if (wsc_len > wpabuf_len(wps) - 2) {
2567 wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
2568 "in rt Wi-Fi Handover Request Message", wsc_len);
2569 goto out;
2570 }
2571 pos += 2;
2572
2573 wpa_hexdump(MSG_DEBUG,
2574 "WPS: WSC attributes in Wi-Fi Handover Request Message",
2575 pos, wsc_len);
2576 if (wsc_len < wpabuf_len(wps) - 2) {
2577 wpa_hexdump(MSG_DEBUG,
2578 "WPS: Ignore extra data after WSC attributes",
2579 pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
2580 }
2581
2582 wpabuf_set(&msg, pos, wsc_len);
2583 ret = wps_parse_msg(&msg, &attr);
2584 if (ret < 0) {
2585 wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
2586 "Wi-Fi Handover Request Message");
2587 goto out;
2588 }
2589
2590 if (attr.oob_dev_password == NULL ||
2591 attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
2592 wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
2593 "included in Wi-Fi Handover Request Message");
2594 ret = -1;
2595 goto out;
2596 }
2597
2598 if (attr.uuid_e == NULL) {
2599 wpa_printf(MSG_DEBUG, "WPS: No UUID-E included in Wi-Fi "
2600 "Handover Request Message");
2601 ret = -1;
2602 goto out;
2603 }
2604
2605 wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", attr.uuid_e, WPS_UUID_LEN);
2606
2607 wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
2608 attr.oob_dev_password, attr.oob_dev_password_len);
2609 dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
2610 WPS_OOB_PUBKEY_HASH_LEN);
2611 if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
2612 wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
2613 "%u in Wi-Fi Handover Request Message", dev_pw_id);
2614 ret = -1;
2615 goto out;
2616 }
2617 wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Public Key hash",
2618 attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
2619
2620 ret = wps_registrar_add_nfc_pw_token(wpa_s->wps->registrar,
2621 attr.oob_dev_password,
2622 DEV_PW_NFC_CONNECTION_HANDOVER,
2623 NULL, 0, 1);
2624
2625out:
2626 wpabuf_free(wps);
2627 return ret;
2628}
2629
Dmitry Shmidt04949592012-07-19 12:16:46 -07002630#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002631
2632
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002633static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s)
2634{
2635 size_t i;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002636 struct os_reltime now;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002637
2638 if (wpa_debug_level > MSG_DEBUG)
2639 return;
2640
2641 if (wpa_s->wps_ap == NULL)
2642 return;
2643
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002644 os_get_reltime(&now);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002645
2646 for (i = 0; i < wpa_s->num_wps_ap; i++) {
2647 struct wps_ap_info *ap = &wpa_s->wps_ap[i];
2648 struct wpa_blacklist *e = wpa_blacklist_get(wpa_s, ap->bssid);
2649
2650 wpa_printf(MSG_DEBUG, "WPS: AP[%d] " MACSTR " type=%d "
2651 "tries=%d last_attempt=%d sec ago blacklist=%d",
2652 (int) i, MAC2STR(ap->bssid), ap->type, ap->tries,
2653 ap->last_attempt.sec > 0 ?
2654 (int) now.sec - (int) ap->last_attempt.sec : -1,
2655 e ? e->count : 0);
2656 }
2657}
2658
2659
2660static struct wps_ap_info * wpas_wps_get_ap_info(struct wpa_supplicant *wpa_s,
2661 const u8 *bssid)
2662{
2663 size_t i;
2664
2665 if (wpa_s->wps_ap == NULL)
2666 return NULL;
2667
2668 for (i = 0; i < wpa_s->num_wps_ap; i++) {
2669 struct wps_ap_info *ap = &wpa_s->wps_ap[i];
2670 if (os_memcmp(ap->bssid, bssid, ETH_ALEN) == 0)
2671 return ap;
2672 }
2673
2674 return NULL;
2675}
2676
2677
2678static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
2679 struct wpa_scan_res *res)
2680{
2681 struct wpabuf *wps;
2682 enum wps_ap_info_type type;
2683 struct wps_ap_info *ap;
2684 int r;
2685
2686 if (wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE) == NULL)
2687 return;
2688
2689 wps = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
2690 if (wps == NULL)
2691 return;
2692
2693 r = wps_is_addr_authorized(wps, wpa_s->own_addr, 1);
2694 if (r == 2)
2695 type = WPS_AP_SEL_REG_OUR;
2696 else if (r == 1)
2697 type = WPS_AP_SEL_REG;
2698 else
2699 type = WPS_AP_NOT_SEL_REG;
2700
2701 wpabuf_free(wps);
2702
2703 ap = wpas_wps_get_ap_info(wpa_s, res->bssid);
2704 if (ap) {
2705 if (ap->type != type) {
2706 wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR
2707 " changed type %d -> %d",
2708 MAC2STR(res->bssid), ap->type, type);
2709 ap->type = type;
2710 if (type != WPS_AP_NOT_SEL_REG)
2711 wpa_blacklist_del(wpa_s, ap->bssid);
2712 }
2713 return;
2714 }
2715
2716 ap = os_realloc_array(wpa_s->wps_ap, wpa_s->num_wps_ap + 1,
2717 sizeof(struct wps_ap_info));
2718 if (ap == NULL)
2719 return;
2720
2721 wpa_s->wps_ap = ap;
2722 ap = &wpa_s->wps_ap[wpa_s->num_wps_ap];
2723 wpa_s->num_wps_ap++;
2724
2725 os_memset(ap, 0, sizeof(*ap));
2726 os_memcpy(ap->bssid, res->bssid, ETH_ALEN);
2727 ap->type = type;
2728 wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " type %d added",
2729 MAC2STR(ap->bssid), ap->type);
2730}
2731
2732
2733void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
2734 struct wpa_scan_results *scan_res)
2735{
2736 size_t i;
2737
2738 for (i = 0; i < scan_res->num; i++)
2739 wpas_wps_update_ap_info_bss(wpa_s, scan_res->res[i]);
2740
2741 wpas_wps_dump_ap_info(wpa_s);
2742}
2743
2744
2745void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid)
2746{
2747 struct wps_ap_info *ap;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002748
2749 wpa_s->after_wps = 0;
2750
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002751 if (!wpa_s->wps_ap_iter)
2752 return;
2753 ap = wpas_wps_get_ap_info(wpa_s, bssid);
2754 if (ap == NULL)
2755 return;
2756 ap->tries++;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002757 os_get_reltime(&ap->last_attempt);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002758}