WPS: Use BSS table instead of raw scan results
[libeap.git] / wpa_supplicant / wps_supplicant.c
1 /*
2  * wpa_supplicant / WPS integration
3  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "includes.h"
16
17 #include "common.h"
18 #include "eloop.h"
19 #include "uuid.h"
20 #include "crypto/dh_group5.h"
21 #include "common/ieee802_11_defs.h"
22 #include "common/ieee802_11_common.h"
23 #include "common/wpa_common.h"
24 #include "common/wpa_ctrl.h"
25 #include "eap_common/eap_wsc_common.h"
26 #include "eap_peer/eap.h"
27 #include "rsn_supp/wpa.h"
28 #include "config.h"
29 #include "wpa_supplicant_i.h"
30 #include "driver_i.h"
31 #include "notify.h"
32 #include "blacklist.h"
33 #include "bss.h"
34 #include "wps_supplicant.h"
35
36
37 #define WPS_PIN_SCAN_IGNORE_SEL_REG 3
38
39 static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
40 static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
41
42
43 int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
44 {
45         if (!wpa_s->wps_success &&
46             wpa_s->current_ssid &&
47             eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
48                 const u8 *bssid = wpa_s->bssid;
49                 if (is_zero_ether_addr(bssid))
50                         bssid = wpa_s->pending_bssid;
51
52                 wpa_printf(MSG_DEBUG, "WPS: PIN registration with " MACSTR
53                            " did not succeed - continue trying to find "
54                            "suitable AP", MAC2STR(bssid));
55                 wpa_blacklist_add(wpa_s, bssid);
56
57                 wpa_supplicant_deauthenticate(wpa_s,
58                                               WLAN_REASON_DEAUTH_LEAVING);
59                 wpa_s->reassociate = 1;
60                 wpa_supplicant_req_scan(wpa_s,
61                                         wpa_s->blacklist_cleared ? 5 : 0, 0);
62                 wpa_s->blacklist_cleared = 0;
63                 return 1;
64         }
65
66         eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
67
68         if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid &&
69             !(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
70                 wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
71                            "try to associate with the received credential");
72                 wpa_supplicant_deauthenticate(wpa_s,
73                                               WLAN_REASON_DEAUTH_LEAVING);
74                 wpa_s->reassociate = 1;
75                 wpa_supplicant_req_scan(wpa_s, 0, 0);
76                 return 1;
77         }
78
79         if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid) {
80                 wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting "
81                            "for external credential processing");
82                 wpas_clear_wps(wpa_s);
83                 wpa_supplicant_deauthenticate(wpa_s,
84                                               WLAN_REASON_DEAUTH_LEAVING);
85                 return 1;
86         }
87
88         return 0;
89 }
90
91
92 static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
93                                          struct wpa_ssid *ssid,
94                                          const struct wps_credential *cred)
95 {
96         struct wpa_driver_capa capa;
97         struct wpa_bss *bss;
98         const u8 *ie;
99         struct wpa_ie_data adv;
100         int wpa2 = 0, ccmp = 0;
101
102         /*
103          * Many existing WPS APs do not know how to negotiate WPA2 or CCMP in
104          * case they are configured for mixed mode operation (WPA+WPA2 and
105          * TKIP+CCMP). Try to use scan results to figure out whether the AP
106          * actually supports stronger security and select that if the client
107          * has support for it, too.
108          */
109
110         if (wpa_drv_get_capa(wpa_s, &capa))
111                 return; /* Unknown what driver supports */
112
113         bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len);
114         if (bss == NULL) {
115                 wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS "
116                            "table - use credential as-is");
117                 return;
118         }
119
120         wpa_printf(MSG_DEBUG, "WPS: AP found from BSS table");
121
122         ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
123         if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0) {
124                 wpa2 = 1;
125                 if (adv.pairwise_cipher & WPA_CIPHER_CCMP)
126                         ccmp = 1;
127         } else {
128                 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
129                 if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0 &&
130                     adv.pairwise_cipher & WPA_CIPHER_CCMP)
131                         ccmp = 1;
132         }
133
134         if (ie == NULL && (ssid->proto & WPA_PROTO_WPA) &&
135             (ssid->pairwise_cipher & WPA_CIPHER_TKIP)) {
136                 /*
137                  * TODO: This could be the initial AP configuration and the
138                  * Beacon contents could change shortly. Should request a new
139                  * scan and delay addition of the network until the updated
140                  * scan results are available.
141                  */
142                 wpa_printf(MSG_DEBUG, "WPS: The AP did not yet advertise WPA "
143                            "support - use credential as-is");
144                 return;
145         }
146
147         if (ccmp && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
148             (ssid->pairwise_cipher & WPA_CIPHER_TKIP) &&
149             (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
150                 wpa_printf(MSG_DEBUG, "WPS: Add CCMP into the credential "
151                            "based on scan results");
152                 if (wpa_s->conf->ap_scan == 1)
153                         ssid->pairwise_cipher |= WPA_CIPHER_CCMP;
154                 else
155                         ssid->pairwise_cipher = WPA_CIPHER_CCMP;
156         }
157
158         if (wpa2 && !(ssid->proto & WPA_PROTO_RSN) &&
159             (ssid->proto & WPA_PROTO_WPA) &&
160             (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP)) {
161                 wpa_printf(MSG_DEBUG, "WPS: Add WPA2 into the credential "
162                            "based on scan results");
163                 if (wpa_s->conf->ap_scan == 1)
164                         ssid->proto |= WPA_PROTO_RSN;
165                 else
166                         ssid->proto = WPA_PROTO_RSN;
167         }
168 }
169
170
171 static int wpa_supplicant_wps_cred(void *ctx,
172                                    const struct wps_credential *cred)
173 {
174         struct wpa_supplicant *wpa_s = ctx;
175         struct wpa_ssid *ssid = wpa_s->current_ssid;
176         u8 key_idx = 0;
177         u16 auth_type;
178
179         if ((wpa_s->conf->wps_cred_processing == 1 ||
180              wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) {
181                 size_t blen = cred->cred_attr_len * 2 + 1;
182                 char *buf = os_malloc(blen);
183                 if (buf) {
184                         wpa_snprintf_hex(buf, blen,
185                                          cred->cred_attr, cred->cred_attr_len);
186                         wpa_msg(wpa_s, MSG_INFO, "%s%s",
187                                 WPS_EVENT_CRED_RECEIVED, buf);
188                         os_free(buf);
189                 }
190
191                 wpas_notify_wps_credential(wpa_s, cred);
192         } else
193                 wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED);
194
195         wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
196                         cred->cred_attr, cred->cred_attr_len);
197
198         if (wpa_s->conf->wps_cred_processing == 1)
199                 return 0;
200
201         wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
202         wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
203                    cred->auth_type);
204         wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
205         wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
206         wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
207                         cred->key, cred->key_len);
208         wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
209                    MAC2STR(cred->mac_addr));
210
211         auth_type = cred->auth_type;
212         if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
213                 wpa_printf(MSG_DEBUG, "WPS: Workaround - convert mixed-mode "
214                            "auth_type into WPA2PSK");
215                 auth_type = WPS_AUTH_WPA2PSK;
216         }
217
218         if (auth_type != WPS_AUTH_OPEN &&
219             auth_type != WPS_AUTH_SHARED &&
220             auth_type != WPS_AUTH_WPAPSK &&
221             auth_type != WPS_AUTH_WPA2PSK) {
222                 wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
223                            "unsupported authentication type 0x%x",
224                            auth_type);
225                 return 0;
226         }
227
228         if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
229                 wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
230                            "on the received credential");
231                 os_free(ssid->eap.identity);
232                 ssid->eap.identity = NULL;
233                 ssid->eap.identity_len = 0;
234                 os_free(ssid->eap.phase1);
235                 ssid->eap.phase1 = NULL;
236                 os_free(ssid->eap.eap_methods);
237                 ssid->eap.eap_methods = NULL;
238         } else {
239                 wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
240                            "received credential");
241                 ssid = wpa_config_add_network(wpa_s->conf);
242                 if (ssid == NULL)
243                         return -1;
244                 wpas_notify_network_added(wpa_s, ssid);
245         }
246
247         wpa_config_set_network_defaults(ssid);
248
249         os_free(ssid->ssid);
250         ssid->ssid = os_malloc(cred->ssid_len);
251         if (ssid->ssid) {
252                 os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len);
253                 ssid->ssid_len = cred->ssid_len;
254         }
255
256         switch (cred->encr_type) {
257         case WPS_ENCR_NONE:
258                 break;
259         case WPS_ENCR_WEP:
260                 if (cred->key_len <= 0)
261                         break;
262                 if (cred->key_len != 5 && cred->key_len != 13 &&
263                     cred->key_len != 10 && cred->key_len != 26) {
264                         wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key length "
265                                    "%lu", (unsigned long) cred->key_len);
266                         return -1;
267                 }
268                 if (cred->key_idx > NUM_WEP_KEYS) {
269                         wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key index %d",
270                                    cred->key_idx);
271                         return -1;
272                 }
273                 if (cred->key_idx)
274                         key_idx = cred->key_idx - 1;
275                 if (cred->key_len == 10 || cred->key_len == 26) {
276                         if (hexstr2bin((char *) cred->key,
277                                        ssid->wep_key[key_idx],
278                                        cred->key_len / 2) < 0) {
279                                 wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key "
280                                            "%d", key_idx);
281                                 return -1;
282                         }
283                         ssid->wep_key_len[key_idx] = cred->key_len / 2;
284                 } else {
285                         os_memcpy(ssid->wep_key[key_idx], cred->key,
286                                   cred->key_len);
287                         ssid->wep_key_len[key_idx] = cred->key_len;
288                 }
289                 ssid->wep_tx_keyidx = key_idx;
290                 break;
291         case WPS_ENCR_TKIP:
292                 ssid->pairwise_cipher = WPA_CIPHER_TKIP;
293                 break;
294         case WPS_ENCR_AES:
295                 ssid->pairwise_cipher = WPA_CIPHER_CCMP;
296                 break;
297         }
298
299         switch (auth_type) {
300         case WPS_AUTH_OPEN:
301                 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
302                 ssid->key_mgmt = WPA_KEY_MGMT_NONE;
303                 ssid->proto = 0;
304                 break;
305         case WPS_AUTH_SHARED:
306                 ssid->auth_alg = WPA_AUTH_ALG_SHARED;
307                 ssid->key_mgmt = WPA_KEY_MGMT_NONE;
308                 ssid->proto = 0;
309                 break;
310         case WPS_AUTH_WPAPSK:
311                 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
312                 ssid->key_mgmt = WPA_KEY_MGMT_PSK;
313                 ssid->proto = WPA_PROTO_WPA;
314                 break;
315         case WPS_AUTH_WPA:
316                 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
317                 ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
318                 ssid->proto = WPA_PROTO_WPA;
319                 break;
320         case WPS_AUTH_WPA2:
321                 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
322                 ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
323                 ssid->proto = WPA_PROTO_RSN;
324                 break;
325         case WPS_AUTH_WPA2PSK:
326                 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
327                 ssid->key_mgmt = WPA_KEY_MGMT_PSK;
328                 ssid->proto = WPA_PROTO_RSN;
329                 break;
330         }
331
332         if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) {
333                 if (cred->key_len == 2 * PMK_LEN) {
334                         if (hexstr2bin((const char *) cred->key, ssid->psk,
335                                        PMK_LEN)) {
336                                 wpa_printf(MSG_ERROR, "WPS: Invalid Network "
337                                            "Key");
338                                 return -1;
339                         }
340                         ssid->psk_set = 1;
341                 } else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) {
342                         os_free(ssid->passphrase);
343                         ssid->passphrase = os_malloc(cred->key_len + 1);
344                         if (ssid->passphrase == NULL)
345                                 return -1;
346                         os_memcpy(ssid->passphrase, cred->key, cred->key_len);
347                         ssid->passphrase[cred->key_len] = '\0';
348                         wpa_config_update_psk(ssid);
349                 } else {
350                         wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
351                                    "length %lu",
352                                    (unsigned long) cred->key_len);
353                         return -1;
354                 }
355         }
356
357         wpas_wps_security_workaround(wpa_s, ssid, cred);
358
359 #ifndef CONFIG_NO_CONFIG_WRITE
360         if (wpa_s->conf->update_config &&
361             wpa_config_write(wpa_s->confname, wpa_s->conf)) {
362                 wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration");
363                 return -1;
364         }
365 #endif /* CONFIG_NO_CONFIG_WRITE */
366
367         return 0;
368 }
369
370
371 static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
372                                          struct wps_event_m2d *m2d)
373 {
374         wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_M2D
375                 "dev_password_id=%d config_error=%d",
376                 m2d->dev_password_id, m2d->config_error);
377         wpas_notify_wps_event_m2d(wpa_s, m2d);
378 }
379
380
381 static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
382                                           struct wps_event_fail *fail)
383 {
384         wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL "msg=%d", fail->msg);
385         wpas_clear_wps(wpa_s);
386         wpas_notify_wps_event_fail(wpa_s, fail);
387 }
388
389
390 static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
391 {
392         wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
393         wpa_s->wps_success = 1;
394         wpas_notify_wps_event_success(wpa_s);
395 }
396
397
398 static void wpa_supplicant_wps_event_er_ap_add(struct wpa_supplicant *wpa_s,
399                                                struct wps_event_er_ap *ap)
400 {
401         char uuid_str[100];
402         char dev_type[WPS_DEV_TYPE_BUFSIZE];
403
404         uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str));
405         if (ap->pri_dev_type)
406                 wps_dev_type_bin2str(ap->pri_dev_type, dev_type,
407                                      sizeof(dev_type));
408         else
409                 dev_type[0] = '\0';
410
411         wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_ADD "%s " MACSTR
412                 " pri_dev_type=%s wps_state=%d |%s|%s|%s|%s|%s|%s|",
413                 uuid_str, MAC2STR(ap->mac_addr), dev_type, ap->wps_state,
414                 ap->friendly_name ? ap->friendly_name : "",
415                 ap->manufacturer ? ap->manufacturer : "",
416                 ap->model_description ? ap->model_description : "",
417                 ap->model_name ? ap->model_name : "",
418                 ap->manufacturer_url ? ap->manufacturer_url : "",
419                 ap->model_url ? ap->model_url : "");
420 }
421
422
423 static void wpa_supplicant_wps_event_er_ap_remove(struct wpa_supplicant *wpa_s,
424                                                   struct wps_event_er_ap *ap)
425 {
426         char uuid_str[100];
427         uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str));
428         wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_REMOVE "%s", uuid_str);
429 }
430
431
432 static void wpa_supplicant_wps_event_er_enrollee_add(
433         struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee)
434 {
435         char uuid_str[100];
436         char dev_type[WPS_DEV_TYPE_BUFSIZE];
437
438         uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str));
439         if (enrollee->pri_dev_type)
440                 wps_dev_type_bin2str(enrollee->pri_dev_type, dev_type,
441                                      sizeof(dev_type));
442         else
443                 dev_type[0] = '\0';
444
445         wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_ADD "%s " MACSTR
446                 " M1=%d config_methods=0x%x dev_passwd_id=%d pri_dev_type=%s "
447                 "|%s|%s|%s|%s|%s|",
448                 uuid_str, MAC2STR(enrollee->mac_addr), enrollee->m1_received,
449                 enrollee->config_methods, enrollee->dev_passwd_id, dev_type,
450                 enrollee->dev_name ? enrollee->dev_name : "",
451                 enrollee->manufacturer ? enrollee->manufacturer : "",
452                 enrollee->model_name ? enrollee->model_name : "",
453                 enrollee->model_number ? enrollee->model_number : "",
454                 enrollee->serial_number ? enrollee->serial_number : "");
455 }
456
457
458 static void wpa_supplicant_wps_event_er_enrollee_remove(
459         struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee)
460 {
461         char uuid_str[100];
462         uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str));
463         wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_REMOVE "%s " MACSTR,
464                 uuid_str, MAC2STR(enrollee->mac_addr));
465 }
466
467
468 static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
469                                      union wps_event_data *data)
470 {
471         struct wpa_supplicant *wpa_s = ctx;
472         switch (event) {
473         case WPS_EV_M2D:
474                 wpa_supplicant_wps_event_m2d(wpa_s, &data->m2d);
475                 break;
476         case WPS_EV_FAIL:
477                 wpa_supplicant_wps_event_fail(wpa_s, &data->fail);
478                 break;
479         case WPS_EV_SUCCESS:
480                 wpa_supplicant_wps_event_success(wpa_s);
481                 break;
482         case WPS_EV_PWD_AUTH_FAIL:
483                 break;
484         case WPS_EV_PBC_OVERLAP:
485                 break;
486         case WPS_EV_PBC_TIMEOUT:
487                 break;
488         case WPS_EV_ER_AP_ADD:
489                 wpa_supplicant_wps_event_er_ap_add(wpa_s, &data->ap);
490                 break;
491         case WPS_EV_ER_AP_REMOVE:
492                 wpa_supplicant_wps_event_er_ap_remove(wpa_s, &data->ap);
493                 break;
494         case WPS_EV_ER_ENROLLEE_ADD:
495                 wpa_supplicant_wps_event_er_enrollee_add(wpa_s,
496                                                          &data->enrollee);
497                 break;
498         case WPS_EV_ER_ENROLLEE_REMOVE:
499                 wpa_supplicant_wps_event_er_enrollee_remove(wpa_s,
500                                                             &data->enrollee);
501                 break;
502         }
503 }
504
505
506 enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid)
507 {
508         if (eap_is_wps_pbc_enrollee(&ssid->eap) ||
509             eap_is_wps_pin_enrollee(&ssid->eap))
510                 return WPS_REQ_ENROLLEE;
511         else
512                 return WPS_REQ_REGISTRAR;
513 }
514
515
516 static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
517 {
518         int id;
519         struct wpa_ssid *ssid, *remove_ssid = NULL;
520
521         eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
522
523         /* Remove any existing WPS network from configuration */
524         ssid = wpa_s->conf->ssid;
525         while (ssid) {
526                 if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
527                         if (ssid == wpa_s->current_ssid) {
528                                 wpa_s->current_ssid = NULL;
529                                 if (ssid != NULL)
530                                         wpas_notify_network_changed(wpa_s);
531                         }
532                         id = ssid->id;
533                         remove_ssid = ssid;
534                 } else
535                         id = -1;
536                 ssid = ssid->next;
537                 if (id >= 0) {
538                         wpas_notify_network_removed(wpa_s, remove_ssid);
539                         wpa_config_remove_network(wpa_s->conf, id);
540                 }
541         }
542 }
543
544
545 static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
546 {
547         struct wpa_supplicant *wpa_s = eloop_ctx;
548         wpa_printf(MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed "
549                    "out");
550         wpas_clear_wps(wpa_s);
551 }
552
553
554 static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
555                                               int registrar, const u8 *bssid)
556 {
557         struct wpa_ssid *ssid;
558
559         ssid = wpa_config_add_network(wpa_s->conf);
560         if (ssid == NULL)
561                 return NULL;
562         wpas_notify_network_added(wpa_s, ssid);
563         wpa_config_set_network_defaults(ssid);
564         if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 ||
565             wpa_config_set(ssid, "eap", "WSC", 0) < 0 ||
566             wpa_config_set(ssid, "identity", registrar ?
567                            "\"" WSC_ID_REGISTRAR "\"" :
568                            "\"" WSC_ID_ENROLLEE "\"", 0) < 0) {
569                 wpas_notify_network_removed(wpa_s, ssid);
570                 wpa_config_remove_network(wpa_s->conf, ssid->id);
571                 return NULL;
572         }
573
574         if (bssid) {
575                 struct wpa_bss *bss;
576                 int count = 0;
577
578                 os_memcpy(ssid->bssid, bssid, ETH_ALEN);
579                 ssid->bssid_set = 1;
580
581                 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
582                         if (os_memcmp(bssid, bss->bssid, ETH_ALEN) != 0)
583                                 continue;
584
585                         os_free(ssid->ssid);
586                         ssid->ssid = os_malloc(bss->ssid_len);
587                         if (ssid->ssid == NULL)
588                                 break;
589                         os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
590                         ssid->ssid_len = bss->ssid_len;
591                         wpa_hexdump_ascii(MSG_DEBUG, "WPS: Picked SSID from "
592                                           "scan results",
593                                           ssid->ssid, ssid->ssid_len);
594                         count++;
595                 }
596
597                 if (count > 1) {
598                         wpa_printf(MSG_DEBUG, "WPS: More than one SSID found "
599                                    "for the AP; use wildcard");
600                         os_free(ssid->ssid);
601                         ssid->ssid = NULL;
602                         ssid->ssid_len = 0;
603                 }
604         }
605
606         return ssid;
607 }
608
609
610 static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
611                              struct wpa_ssid *selected)
612 {
613         struct wpa_ssid *ssid;
614
615         /* Mark all other networks disabled and trigger reassociation */
616         ssid = wpa_s->conf->ssid;
617         while (ssid) {
618                 int was_disabled = ssid->disabled;
619                 ssid->disabled = ssid != selected;
620                 if (was_disabled != ssid->disabled)
621                         wpas_notify_network_enabled_changed(wpa_s, ssid);
622                 ssid = ssid->next;
623         }
624         wpa_s->disconnected = 0;
625         wpa_s->reassociate = 1;
626         wpa_s->scan_runs = 0;
627         wpa_s->wps_success = 0;
628         wpa_s->blacklist_cleared = 0;
629         wpa_supplicant_req_scan(wpa_s, 0, 0);
630 }
631
632
633 int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid)
634 {
635         struct wpa_ssid *ssid;
636         wpas_clear_wps(wpa_s);
637         ssid = wpas_wps_add_network(wpa_s, 0, bssid);
638         if (ssid == NULL)
639                 return -1;
640         wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0);
641         eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
642                                wpa_s, NULL);
643         wpas_wps_reassoc(wpa_s, ssid);
644         return 0;
645 }
646
647
648 int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
649                        const char *pin)
650 {
651         struct wpa_ssid *ssid;
652         char val[128];
653         unsigned int rpin = 0;
654
655         wpas_clear_wps(wpa_s);
656         ssid = wpas_wps_add_network(wpa_s, 0, bssid);
657         if (ssid == NULL)
658                 return -1;
659         if (pin)
660                 os_snprintf(val, sizeof(val), "\"pin=%s\"", pin);
661         else {
662                 rpin = wps_generate_pin();
663                 os_snprintf(val, sizeof(val), "\"pin=%08d\"", rpin);
664         }
665         wpa_config_set(ssid, "phase1", val, 0);
666         eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
667                                wpa_s, NULL);
668         wpas_wps_reassoc(wpa_s, ssid);
669         return rpin;
670 }
671
672
673 #ifdef CONFIG_WPS_OOB
674 int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
675                        char *path, char *method, char *name)
676 {
677         struct wps_context *wps = wpa_s->wps;
678         struct oob_device_data *oob_dev;
679
680         oob_dev = wps_get_oob_device(device_type);
681         if (oob_dev == NULL)
682                 return -1;
683         oob_dev->device_path = path;
684         oob_dev->device_name = name;
685         wps->oob_conf.oob_method = wps_get_oob_method(method);
686
687         if (wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E) {
688                 /*
689                  * Use pre-configured DH keys in order to be able to write the
690                  * key hash into the OOB file.
691                  */
692                 wpabuf_free(wps->dh_pubkey);
693                 wpabuf_free(wps->dh_privkey);
694                 wps->dh_privkey = NULL;
695                 wps->dh_pubkey = NULL;
696                 dh5_free(wps->dh_ctx);
697                 wps->dh_ctx = dh5_init(&wps->dh_privkey, &wps->dh_pubkey);
698                 wps->dh_pubkey = wpabuf_zeropad(wps->dh_pubkey, 192);
699                 if (wps->dh_ctx == NULL || wps->dh_pubkey == NULL) {
700                         wpa_printf(MSG_ERROR, "WPS: Failed to initialize "
701                                    "Diffie-Hellman handshake");
702                         return -1;
703                 }
704         }
705
706         if (wps->oob_conf.oob_method == OOB_METHOD_CRED)
707                 wpas_clear_wps(wpa_s);
708
709         if (wps_process_oob(wps, oob_dev, 0) < 0)
710                 return -1;
711
712         if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
713              wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
714             wpas_wps_start_pin(wpa_s, NULL,
715                                wpabuf_head(wps->oob_conf.dev_password)) < 0)
716                         return -1;
717
718         return 0;
719 }
720 #endif /* CONFIG_WPS_OOB */
721
722
723 int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
724                        const char *pin, struct wps_new_ap_settings *settings)
725 {
726         struct wpa_ssid *ssid;
727         char val[200];
728         char *pos, *end;
729         int res;
730
731         if (!pin)
732                 return -1;
733         wpas_clear_wps(wpa_s);
734         ssid = wpas_wps_add_network(wpa_s, 1, bssid);
735         if (ssid == NULL)
736                 return -1;
737         pos = val;
738         end = pos + sizeof(val);
739         res = os_snprintf(pos, end - pos, "\"pin=%s", pin);
740         if (res < 0 || res >= end - pos)
741                 return -1;
742         pos += res;
743         if (settings) {
744                 res = os_snprintf(pos, end - pos, " new_ssid=%s new_auth=%s "
745                                   "new_encr=%s new_key=%s",
746                                   settings->ssid_hex, settings->auth,
747                                   settings->encr, settings->key_hex);
748                 if (res < 0 || res >= end - pos)
749                         return -1;
750                 pos += res;
751         }
752         res = os_snprintf(pos, end - pos, "\"");
753         if (res < 0 || res >= end - pos)
754                 return -1;
755         wpa_config_set(ssid, "phase1", val, 0);
756         eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
757                                wpa_s, NULL);
758         wpas_wps_reassoc(wpa_s, ssid);
759         return 0;
760 }
761
762
763 static int wpas_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
764                                size_t psk_len)
765 {
766         wpa_printf(MSG_DEBUG, "WPS: Received new WPA/WPA2-PSK from WPS for "
767                    "STA " MACSTR, MAC2STR(mac_addr));
768         wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
769
770         /* TODO */
771
772         return 0;
773 }
774
775
776 static void wpas_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
777                                    const struct wps_device_data *dev)
778 {
779         char uuid[40], txt[400];
780         int len;
781         char devtype[WPS_DEV_TYPE_BUFSIZE];
782         if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
783                 return;
784         wpa_printf(MSG_DEBUG, "WPS: PIN needed for UUID-E %s", uuid);
785         len = os_snprintf(txt, sizeof(txt), "WPS-EVENT-PIN-NEEDED %s " MACSTR
786                           " [%s|%s|%s|%s|%s|%s]",
787                           uuid, MAC2STR(dev->mac_addr), dev->device_name,
788                           dev->manufacturer, dev->model_name,
789                           dev->model_number, dev->serial_number,
790                           wps_dev_type_bin2str(dev->pri_dev_type, devtype,
791                                                sizeof(devtype)));
792         if (len > 0 && len < (int) sizeof(txt))
793                 wpa_printf(MSG_INFO, "%s", txt);
794 }
795
796
797 static void wpas_wps_set_sel_reg_cb(void *ctx, int sel_reg, u16 dev_passwd_id,
798                                     u16 sel_reg_config_methods)
799 {
800 #ifdef CONFIG_WPS_ER
801         struct wpa_supplicant *wpa_s = ctx;
802
803         if (wpa_s->wps_er == NULL)
804                 return;
805         wps_er_set_sel_reg(wpa_s->wps_er, sel_reg, dev_passwd_id,
806                            sel_reg_config_methods);
807 #endif /* CONFIG_WPS_ER */
808 }
809
810
811 int wpas_wps_init(struct wpa_supplicant *wpa_s)
812 {
813         struct wps_context *wps;
814         struct wps_registrar_config rcfg;
815
816         wps = os_zalloc(sizeof(*wps));
817         if (wps == NULL)
818                 return -1;
819
820         wps->cred_cb = wpa_supplicant_wps_cred;
821         wps->event_cb = wpa_supplicant_wps_event;
822         wps->cb_ctx = wpa_s;
823
824         wps->dev.device_name = wpa_s->conf->device_name;
825         wps->dev.manufacturer = wpa_s->conf->manufacturer;
826         wps->dev.model_name = wpa_s->conf->model_name;
827         wps->dev.model_number = wpa_s->conf->model_number;
828         wps->dev.serial_number = wpa_s->conf->serial_number;
829         wps->config_methods =
830                 wps_config_methods_str2bin(wpa_s->conf->config_methods);
831         if (wpa_s->conf->device_type &&
832             wps_dev_type_str2bin(wpa_s->conf->device_type,
833                                  wps->dev.pri_dev_type) < 0) {
834                 wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
835                 os_free(wps);
836                 return -1;
837         }
838         wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
839         wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ; /* TODO: config */
840         os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
841         if (is_nil_uuid(wpa_s->conf->uuid)) {
842                 uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid);
843                 wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC address",
844                             wps->uuid, WPS_UUID_LEN);
845         } else
846                 os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
847
848         wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
849         wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
850
851         os_memset(&rcfg, 0, sizeof(rcfg));
852         rcfg.new_psk_cb = wpas_wps_new_psk_cb;
853         rcfg.pin_needed_cb = wpas_wps_pin_needed_cb;
854         rcfg.set_sel_reg_cb = wpas_wps_set_sel_reg_cb;
855         rcfg.cb_ctx = wpa_s;
856
857         wps->registrar = wps_registrar_init(wps, &rcfg);
858         if (wps->registrar == NULL) {
859                 wpa_printf(MSG_DEBUG, "Failed to initialize WPS Registrar");
860                 os_free(wps);
861                 return -1;
862         }
863
864         wpa_s->wps = wps;
865
866         return 0;
867 }
868
869
870 void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
871 {
872         eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
873
874         if (wpa_s->wps == NULL)
875                 return;
876
877 #ifdef CONFIG_WPS_ER
878         wps_er_deinit(wpa_s->wps_er, NULL, NULL);
879         wpa_s->wps_er = NULL;
880 #endif /* CONFIG_WPS_ER */
881
882         wps_registrar_deinit(wpa_s->wps->registrar);
883         wpabuf_free(wpa_s->wps->dh_pubkey);
884         wpabuf_free(wpa_s->wps->dh_privkey);
885         wpabuf_free(wpa_s->wps->oob_conf.pubkey_hash);
886         wpabuf_free(wpa_s->wps->oob_conf.dev_password);
887         os_free(wpa_s->wps->network_key);
888         os_free(wpa_s->wps);
889         wpa_s->wps = NULL;
890 }
891
892
893 int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
894                             struct wpa_ssid *ssid, struct wpa_scan_res *bss)
895 {
896         struct wpabuf *wps_ie;
897
898         if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
899                 return -1;
900
901         wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
902         if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
903                 if (!wps_ie) {
904                         wpa_printf(MSG_DEBUG, "   skip - non-WPS AP");
905                         return 0;
906                 }
907
908                 if (!wps_is_selected_pbc_registrar(wps_ie)) {
909                         wpa_printf(MSG_DEBUG, "   skip - WPS AP "
910                                    "without active PBC Registrar");
911                         wpabuf_free(wps_ie);
912                         return 0;
913                 }
914
915                 /* TODO: overlap detection */
916                 wpa_printf(MSG_DEBUG, "   selected based on WPS IE "
917                            "(Active PBC)");
918                 wpabuf_free(wps_ie);
919                 return 1;
920         }
921
922         if (eap_is_wps_pin_enrollee(&ssid->eap)) {
923                 if (!wps_ie) {
924                         wpa_printf(MSG_DEBUG, "   skip - non-WPS AP");
925                         return 0;
926                 }
927
928                 /*
929                  * Start with WPS APs that advertise active PIN Registrar and
930                  * allow any WPS AP after third scan since some APs do not set
931                  * Selected Registrar attribute properly when using external
932                  * Registrar.
933                  */
934                 if (!wps_is_selected_pin_registrar(wps_ie)) {
935                         if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) {
936                                 wpa_printf(MSG_DEBUG, "   skip - WPS AP "
937                                            "without active PIN Registrar");
938                                 wpabuf_free(wps_ie);
939                                 return 0;
940                         }
941                         wpa_printf(MSG_DEBUG, "   selected based on WPS IE");
942                 } else {
943                         wpa_printf(MSG_DEBUG, "   selected based on WPS IE "
944                                    "(Active PIN)");
945                 }
946                 wpabuf_free(wps_ie);
947                 return 1;
948         }
949
950         if (wps_ie) {
951                 wpa_printf(MSG_DEBUG, "   selected based on WPS IE");
952                 wpabuf_free(wps_ie);
953                 return 1;
954         }
955
956         return -1;
957 }
958
959
960 int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
961                               struct wpa_ssid *ssid,
962                               struct wpa_scan_res *bss)
963 {
964         struct wpabuf *wps_ie = NULL;
965         int ret = 0;
966
967         if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
968                 wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
969                 if (wps_ie && wps_is_selected_pbc_registrar(wps_ie)) {
970                         /* allow wildcard SSID for WPS PBC */
971                         ret = 1;
972                 }
973         } else if (eap_is_wps_pin_enrollee(&ssid->eap)) {
974                 wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
975                 if (wps_ie &&
976                     (wps_is_selected_pin_registrar(wps_ie) ||
977                      wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) {
978                         /* allow wildcard SSID for WPS PIN */
979                         ret = 1;
980                 }
981         }
982
983         if (!ret && ssid->bssid_set &&
984             os_memcmp(ssid->bssid, bss->bssid, ETH_ALEN) == 0) {
985                 /* allow wildcard SSID due to hardcoded BSSID match */
986                 ret = 1;
987         }
988
989         wpabuf_free(wps_ie);
990
991         return ret;
992 }
993
994
995 int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
996                               struct wpa_scan_res *selected,
997                               struct wpa_ssid *ssid)
998 {
999         const u8 *sel_uuid, *uuid;
1000         size_t i;
1001         struct wpabuf *wps_ie;
1002         int ret = 0;
1003
1004         if (!eap_is_wps_pbc_enrollee(&ssid->eap))
1005                 return 0;
1006
1007         /* Make sure that only one AP is in active PBC mode */
1008         wps_ie = wpa_scan_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE);
1009         if (wps_ie)
1010                 sel_uuid = wps_get_uuid_e(wps_ie);
1011         else
1012                 sel_uuid = NULL;
1013
1014         for (i = 0; i < wpa_s->scan_res->num; i++) {
1015                 struct wpa_scan_res *bss = wpa_s->scan_res->res[i];
1016                 struct wpabuf *ie;
1017                 if (bss == selected)
1018                         continue;
1019                 ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
1020                 if (!ie)
1021                         continue;
1022                 if (!wps_is_selected_pbc_registrar(ie)) {
1023                         wpabuf_free(ie);
1024                         continue;
1025                 }
1026                 uuid = wps_get_uuid_e(ie);
1027                 if (sel_uuid == NULL || uuid == NULL ||
1028                     os_memcmp(sel_uuid, uuid, 16) != 0) {
1029                         ret = 1; /* PBC overlap */
1030                         wpabuf_free(ie);
1031                         break;
1032                 }
1033
1034                 /* TODO: verify that this is reasonable dual-band situation */
1035
1036                 wpabuf_free(ie);
1037         }
1038
1039         wpabuf_free(wps_ie);
1040
1041         return ret;
1042 }
1043
1044
1045 void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s)
1046 {
1047         size_t i;
1048
1049         if (wpa_s->disconnected || wpa_s->wpa_state >= WPA_ASSOCIATED)
1050                 return;
1051
1052         for (i = 0; i < wpa_s->scan_res->num; i++) {
1053                 struct wpa_scan_res *bss = wpa_s->scan_res->res[i];
1054                 struct wpabuf *ie;
1055                 ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
1056                 if (!ie)
1057                         continue;
1058                 if (wps_is_selected_pbc_registrar(ie))
1059                         wpa_msg_ctrl(wpa_s, MSG_INFO,
1060                                      WPS_EVENT_AP_AVAILABLE_PBC);
1061                 else if (wps_is_selected_pin_registrar(ie))
1062                         wpa_msg_ctrl(wpa_s, MSG_INFO,
1063                                      WPS_EVENT_AP_AVAILABLE_PIN);
1064                 else
1065                         wpa_msg_ctrl(wpa_s, MSG_INFO,
1066                                      WPS_EVENT_AP_AVAILABLE);
1067                 wpabuf_free(ie);
1068                 break;
1069         }
1070 }
1071
1072
1073 int wpas_wps_searching(struct wpa_supplicant *wpa_s)
1074 {
1075         struct wpa_ssid *ssid;
1076
1077         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1078                 if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && !ssid->disabled)
1079                         return 1;
1080         }
1081
1082         return 0;
1083 }
1084
1085
1086 int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
1087                               char *end)
1088 {
1089         struct wpabuf *wps_ie;
1090         int ret;
1091
1092         wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, WPS_DEV_OUI_WFA);
1093         if (wps_ie == NULL)
1094                 return 0;
1095
1096         ret = wps_attr_text(wps_ie, buf, end);
1097         wpabuf_free(wps_ie);
1098         return ret;
1099 }
1100
1101
1102 int wpas_wps_er_start(struct wpa_supplicant *wpa_s)
1103 {
1104 #ifdef CONFIG_WPS_ER
1105         if (wpa_s->wps_er) {
1106                 wps_er_refresh(wpa_s->wps_er);
1107                 return 0;
1108         }
1109         wpa_s->wps_er = wps_er_init(wpa_s->wps, wpa_s->ifname);
1110         if (wpa_s->wps_er == NULL)
1111                 return -1;
1112         return 0;
1113 #else /* CONFIG_WPS_ER */
1114         return 0;
1115 #endif /* CONFIG_WPS_ER */
1116 }
1117
1118
1119 int wpas_wps_er_stop(struct wpa_supplicant *wpa_s)
1120 {
1121 #ifdef CONFIG_WPS_ER
1122         wps_er_deinit(wpa_s->wps_er, NULL, NULL);
1123         wpa_s->wps_er = NULL;
1124 #endif /* CONFIG_WPS_ER */
1125         return 0;
1126 }
1127
1128
1129 #ifdef CONFIG_WPS_ER
1130 int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const char *uuid,
1131                         const char *pin)
1132 {
1133         u8 u[UUID_LEN];
1134         int any = 0;
1135
1136         if (os_strcmp(uuid, "any") == 0)
1137                 any = 1;
1138         else if (uuid_str2bin(uuid, u))
1139                 return -1;
1140         return wps_registrar_add_pin(wpa_s->wps->registrar, any ? NULL : u,
1141                                      (const u8 *) pin, os_strlen(pin), 300);
1142 }
1143
1144
1145 int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid)
1146 {
1147         u8 u[UUID_LEN];
1148
1149         if (uuid_str2bin(uuid, u))
1150                 return -1;
1151         return wps_er_pbc(wpa_s->wps_er, u);
1152 }
1153
1154
1155 int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
1156                       const char *pin)
1157 {
1158         u8 u[UUID_LEN];
1159
1160         if (uuid_str2bin(uuid, u))
1161                 return -1;
1162         return wps_er_learn(wpa_s->wps_er, u, (const u8 *) pin,
1163                             os_strlen(pin));
1164 }
1165
1166
1167 static void wpas_wps_terminate_cb(void *ctx)
1168 {
1169         wpa_printf(MSG_DEBUG, "WPS ER: Terminated");
1170         eloop_terminate();
1171 }
1172 #endif /* CONFIG_WPS_ER */
1173
1174
1175 int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s)
1176 {
1177 #ifdef CONFIG_WPS_ER
1178         if (wpa_s->wps_er) {
1179                 wps_er_deinit(wpa_s->wps_er, wpas_wps_terminate_cb, wpa_s);
1180                 wpa_s->wps_er = NULL;
1181                 return 1;
1182         }
1183 #endif /* CONFIG_WPS_ER */
1184         return 0;
1185 }