Rename some src/ap files to avoid duplicate file names
[libeap.git] / src / ap / wps_hostapd.c
1 /*
2  * hostapd / WPS integration
3  * Copyright (c) 2008-2009, 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 "utils/includes.h"
16
17 #include "utils/common.h"
18 #include "utils/eloop.h"
19 #include "utils/uuid.h"
20 #include "crypto/dh_groups.h"
21 #include "common/wpa_ctrl.h"
22 #include "common/ieee802_11_defs.h"
23 #include "common/ieee802_11_common.h"
24 #include "eapol_auth/eapol_auth_sm.h"
25 #include "eapol_auth/eapol_auth_sm_i.h"
26 #include "wps/wps.h"
27 #include "wps/wps_defs.h"
28 #include "wps/wps_dev_attr.h"
29 #include "hostapd.h"
30 #include "ap_config.h"
31 #include "sta_info.h"
32 #include "wps_hostapd.h"
33
34
35 #ifdef CONFIG_WPS_UPNP
36 #include "wps/wps_upnp.h"
37 static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
38                                  struct wps_context *wps);
39 static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
40 #endif /* CONFIG_WPS_UPNP */
41
42 static void hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
43                                      const u8 *ie, size_t ie_len);
44
45
46 static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
47                                   size_t psk_len)
48 {
49         struct hostapd_data *hapd = ctx;
50         struct hostapd_wpa_psk *p;
51         struct hostapd_ssid *ssid = &hapd->conf->ssid;
52
53         wpa_printf(MSG_DEBUG, "Received new WPA/WPA2-PSK from WPS for STA "
54                    MACSTR, MAC2STR(mac_addr));
55         wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
56
57         if (psk_len != PMK_LEN) {
58                 wpa_printf(MSG_DEBUG, "Unexpected PSK length %lu",
59                            (unsigned long) psk_len);
60                 return -1;
61         }
62
63         /* Add the new PSK to runtime PSK list */
64         p = os_zalloc(sizeof(*p));
65         if (p == NULL)
66                 return -1;
67         os_memcpy(p->addr, mac_addr, ETH_ALEN);
68         os_memcpy(p->psk, psk, PMK_LEN);
69
70         p->next = ssid->wpa_psk;
71         ssid->wpa_psk = p;
72
73         if (ssid->wpa_psk_file) {
74                 FILE *f;
75                 char hex[PMK_LEN * 2 + 1];
76                 /* Add the new PSK to PSK list file */
77                 f = fopen(ssid->wpa_psk_file, "a");
78                 if (f == NULL) {
79                         wpa_printf(MSG_DEBUG, "Failed to add the PSK to "
80                                    "'%s'", ssid->wpa_psk_file);
81                         return -1;
82                 }
83
84                 wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len);
85                 fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex);
86                 fclose(f);
87         }
88
89         return 0;
90 }
91
92
93 static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie,
94                                  struct wpabuf *probe_resp_ie)
95 {
96         struct hostapd_data *hapd = ctx;
97         wpabuf_free(hapd->wps_beacon_ie);
98         hapd->wps_beacon_ie = beacon_ie;
99         wpabuf_free(hapd->wps_probe_resp_ie);
100         hapd->wps_probe_resp_ie = probe_resp_ie;
101         return hapd->drv.set_ap_wps_ie(hapd, hapd->wps_beacon_ie,
102                                        hapd->wps_probe_resp_ie);
103 }
104
105
106 static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
107                                       const struct wps_device_data *dev)
108 {
109         struct hostapd_data *hapd = ctx;
110         char uuid[40], txt[400];
111         int len;
112         char devtype[WPS_DEV_TYPE_BUFSIZE];
113         if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
114                 return;
115         wpa_printf(MSG_DEBUG, "WPS: PIN needed for E-UUID %s", uuid);
116         len = os_snprintf(txt, sizeof(txt), WPS_EVENT_PIN_NEEDED
117                           "%s " MACSTR " [%s|%s|%s|%s|%s|%s]",
118                           uuid, MAC2STR(dev->mac_addr), dev->device_name,
119                           dev->manufacturer, dev->model_name,
120                           dev->model_number, dev->serial_number,
121                           wps_dev_type_bin2str(dev->pri_dev_type, devtype,
122                                                sizeof(devtype)));
123         if (len > 0 && len < (int) sizeof(txt))
124                 wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt);
125
126         if (hapd->conf->wps_pin_requests) {
127                 FILE *f;
128                 struct os_time t;
129                 f = fopen(hapd->conf->wps_pin_requests, "a");
130                 if (f == NULL)
131                         return;
132                 os_get_time(&t);
133                 fprintf(f, "%ld\t%s\t" MACSTR "\t%s\t%s\t%s\t%s\t%s"
134                         "\t%s\n",
135                         t.sec, uuid, MAC2STR(dev->mac_addr), dev->device_name,
136                         dev->manufacturer, dev->model_name, dev->model_number,
137                         dev->serial_number,
138                         wps_dev_type_bin2str(dev->pri_dev_type, devtype,
139                                              sizeof(devtype)));
140                 fclose(f);
141         }
142 }
143
144
145 static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
146                                        const u8 *uuid_e)
147 {
148         struct hostapd_data *hapd = ctx;
149         char uuid[40];
150         if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
151                 return;
152         wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s",
153                 MAC2STR(mac_addr), uuid);
154 }
155
156
157 static int str_starts(const char *str, const char *start)
158 {
159         return os_strncmp(str, start, os_strlen(start)) == 0;
160 }
161
162
163 static void wps_reload_config(void *eloop_data, void *user_ctx)
164 {
165         struct hostapd_iface *iface = eloop_data;
166
167         wpa_printf(MSG_DEBUG, "WPS: Reload configuration data");
168         if (iface->reload_config(iface) < 0) {
169                 wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated "
170                            "configuration");
171         }
172 }
173
174
175 static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
176 {
177         struct hostapd_data *hapd = ctx;
178         FILE *oconf, *nconf;
179         size_t len, i;
180         char *tmp_fname;
181         char buf[1024];
182         int multi_bss;
183         int wpa;
184
185         wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
186                         cred->cred_attr, cred->cred_attr_len);
187
188         wpa_printf(MSG_DEBUG, "WPS: Received new AP Settings");
189         wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
190         wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
191                    cred->auth_type);
192         wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
193         wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
194         wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
195                         cred->key, cred->key_len);
196         wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
197                    MAC2STR(cred->mac_addr));
198
199         if ((hapd->conf->wps_cred_processing == 1 ||
200              hapd->conf->wps_cred_processing == 2) && cred->cred_attr) {
201                 size_t blen = cred->cred_attr_len * 2 + 1;
202                 char *_buf = os_malloc(blen);
203                 if (_buf) {
204                         wpa_snprintf_hex(_buf, blen,
205                                          cred->cred_attr, cred->cred_attr_len);
206                         wpa_msg(hapd->msg_ctx, MSG_INFO, "%s%s",
207                                 WPS_EVENT_NEW_AP_SETTINGS, _buf);
208                         os_free(_buf);
209                 }
210         } else
211                 wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS);
212
213         if (hapd->conf->wps_cred_processing == 1)
214                 return 0;
215
216         os_memcpy(hapd->wps->ssid, cred->ssid, cred->ssid_len);
217         hapd->wps->ssid_len = cred->ssid_len;
218         hapd->wps->encr_types = cred->encr_type;
219         hapd->wps->auth_types = cred->auth_type;
220         if (cred->key_len == 0) {
221                 os_free(hapd->wps->network_key);
222                 hapd->wps->network_key = NULL;
223                 hapd->wps->network_key_len = 0;
224         } else {
225                 if (hapd->wps->network_key == NULL ||
226                     hapd->wps->network_key_len < cred->key_len) {
227                         hapd->wps->network_key_len = 0;
228                         os_free(hapd->wps->network_key);
229                         hapd->wps->network_key = os_malloc(cred->key_len);
230                         if (hapd->wps->network_key == NULL)
231                                 return -1;
232                 }
233                 hapd->wps->network_key_len = cred->key_len;
234                 os_memcpy(hapd->wps->network_key, cred->key, cred->key_len);
235         }
236         hapd->wps->wps_state = WPS_STATE_CONFIGURED;
237
238         len = os_strlen(hapd->iface->config_fname) + 5;
239         tmp_fname = os_malloc(len);
240         if (tmp_fname == NULL)
241                 return -1;
242         os_snprintf(tmp_fname, len, "%s-new", hapd->iface->config_fname);
243
244         oconf = fopen(hapd->iface->config_fname, "r");
245         if (oconf == NULL) {
246                 wpa_printf(MSG_WARNING, "WPS: Could not open current "
247                            "configuration file");
248                 os_free(tmp_fname);
249                 return -1;
250         }
251
252         nconf = fopen(tmp_fname, "w");
253         if (nconf == NULL) {
254                 wpa_printf(MSG_WARNING, "WPS: Could not write updated "
255                            "configuration file");
256                 os_free(tmp_fname);
257                 fclose(oconf);
258                 return -1;
259         }
260
261         fprintf(nconf, "# WPS configuration - START\n");
262
263         fprintf(nconf, "wps_state=2\n");
264
265         fprintf(nconf, "ssid=");
266         for (i = 0; i < cred->ssid_len; i++)
267                 fputc(cred->ssid[i], nconf);
268         fprintf(nconf, "\n");
269
270         if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
271             (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
272                 wpa = 3;
273         else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
274                 wpa = 2;
275         else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
276                 wpa = 1;
277         else
278                 wpa = 0;
279
280         if (wpa) {
281                 char *prefix;
282                 fprintf(nconf, "wpa=%d\n", wpa);
283
284                 fprintf(nconf, "wpa_key_mgmt=");
285                 prefix = "";
286                 if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA)) {
287                         fprintf(nconf, "WPA-EAP");
288                         prefix = " ";
289                 }
290                 if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
291                         fprintf(nconf, "%sWPA-PSK", prefix);
292                 fprintf(nconf, "\n");
293
294                 fprintf(nconf, "wpa_pairwise=");
295                 prefix = "";
296                 if (cred->encr_type & WPS_ENCR_AES) {
297                         fprintf(nconf, "CCMP");
298                         prefix = " ";
299                 }
300                 if (cred->encr_type & WPS_ENCR_TKIP) {
301                         fprintf(nconf, "%sTKIP", prefix);
302                 }
303                 fprintf(nconf, "\n");
304
305                 if (cred->key_len >= 8 && cred->key_len < 64) {
306                         fprintf(nconf, "wpa_passphrase=");
307                         for (i = 0; i < cred->key_len; i++)
308                                 fputc(cred->key[i], nconf);
309                         fprintf(nconf, "\n");
310                 } else if (cred->key_len == 64) {
311                         fprintf(nconf, "wpa_psk=");
312                         for (i = 0; i < cred->key_len; i++)
313                                 fputc(cred->key[i], nconf);
314                         fprintf(nconf, "\n");
315                 } else {
316                         wpa_printf(MSG_WARNING, "WPS: Invalid key length %lu "
317                                    "for WPA/WPA2",
318                                    (unsigned long) cred->key_len);
319                 }
320
321                 fprintf(nconf, "auth_algs=1\n");
322         } else {
323                 if ((cred->auth_type & WPS_AUTH_OPEN) &&
324                     (cred->auth_type & WPS_AUTH_SHARED))
325                         fprintf(nconf, "auth_algs=3\n");
326                 else if (cred->auth_type & WPS_AUTH_SHARED)
327                         fprintf(nconf, "auth_algs=2\n");
328                 else
329                         fprintf(nconf, "auth_algs=1\n");
330
331                 if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx <= 4) {
332                         int key_idx = cred->key_idx;
333                         if (key_idx)
334                                 key_idx--;
335                         fprintf(nconf, "wep_default_key=%d\n", key_idx);
336                         fprintf(nconf, "wep_key%d=", key_idx);
337                         if (cred->key_len == 10 || cred->key_len == 26) {
338                                 /* WEP key as a hex string */
339                                 for (i = 0; i < cred->key_len; i++)
340                                         fputc(cred->key[i], nconf);
341                         } else {
342                                 /* Raw WEP key; convert to hex */
343                                 for (i = 0; i < cred->key_len; i++)
344                                         fprintf(nconf, "%02x", cred->key[i]);
345                         }
346                         fprintf(nconf, "\n");
347                 }
348         }
349
350         fprintf(nconf, "# WPS configuration - END\n");
351
352         multi_bss = 0;
353         while (fgets(buf, sizeof(buf), oconf)) {
354                 if (os_strncmp(buf, "bss=", 4) == 0)
355                         multi_bss = 1;
356                 if (!multi_bss &&
357                     (str_starts(buf, "ssid=") ||
358                      str_starts(buf, "auth_algs=") ||
359                      str_starts(buf, "wps_state=") ||
360                      str_starts(buf, "wpa=") ||
361                      str_starts(buf, "wpa_psk=") ||
362                      str_starts(buf, "wpa_pairwise=") ||
363                      str_starts(buf, "rsn_pairwise=") ||
364                      str_starts(buf, "wpa_key_mgmt=") ||
365                      str_starts(buf, "wpa_passphrase="))) {
366                         fprintf(nconf, "#WPS# %s", buf);
367                 } else
368                         fprintf(nconf, "%s", buf);
369         }
370
371         fclose(nconf);
372         fclose(oconf);
373
374         if (rename(tmp_fname, hapd->iface->config_fname) < 0) {
375                 wpa_printf(MSG_WARNING, "WPS: Failed to rename the updated "
376                            "configuration file: %s", strerror(errno));
377                 os_free(tmp_fname);
378                 return -1;
379         }
380
381         os_free(tmp_fname);
382
383         /* Schedule configuration reload after short period of time to allow
384          * EAP-WSC to be finished.
385          */
386         eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
387                                NULL);
388
389         /* TODO: dualband AP may need to update multiple configuration files */
390
391         wpa_printf(MSG_DEBUG, "WPS: AP configuration updated");
392
393         return 0;
394 }
395
396
397 static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
398                                   struct wps_event_pwd_auth_fail *data)
399 {
400         FILE *f;
401
402         if (!data->enrollee)
403                 return;
404
405         /*
406          * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup
407          * if this happens multiple times.
408          */
409         hapd->ap_pin_failures++;
410         if (hapd->ap_pin_failures < 4)
411                 return;
412
413         wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED);
414         hapd->wps->ap_setup_locked = 1;
415
416         wps_registrar_update_ie(hapd->wps->registrar);
417
418         if (hapd->conf->wps_cred_processing == 1)
419                 return;
420
421         f = fopen(hapd->iface->config_fname, "a");
422         if (f == NULL) {
423                 wpa_printf(MSG_WARNING, "WPS: Could not append to the current "
424                            "configuration file");
425                 return;
426         }
427
428         fprintf(f, "# WPS AP Setup Locked based on possible attack\n");
429         fprintf(f, "ap_setup_locked=1\n");
430         fclose(f);
431
432         /* TODO: dualband AP may need to update multiple configuration files */
433
434         wpa_printf(MSG_DEBUG, "WPS: AP configuration updated");
435 }
436
437
438 static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
439                                  union wps_event_data *data)
440 {
441         struct hostapd_data *hapd = ctx;
442
443         if (event == WPS_EV_PWD_AUTH_FAIL)
444                 hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
445 }
446
447
448 static void hostapd_wps_clear_ies(struct hostapd_data *hapd)
449 {
450         wpabuf_free(hapd->wps_beacon_ie);
451         hapd->wps_beacon_ie = NULL;
452
453         wpabuf_free(hapd->wps_probe_resp_ie);
454         hapd->wps_probe_resp_ie = NULL;
455
456         hapd->drv.set_ap_wps_ie(hapd, NULL, NULL);
457 }
458
459
460 int hostapd_init_wps(struct hostapd_data *hapd,
461                      struct hostapd_bss_config *conf)
462 {
463         struct wps_context *wps;
464         struct wps_registrar_config cfg;
465
466         if (conf->wps_state == 0) {
467                 hostapd_wps_clear_ies(hapd);
468                 return 0;
469         }
470
471         wps = os_zalloc(sizeof(*wps));
472         if (wps == NULL)
473                 return -1;
474
475         wps->cred_cb = hostapd_wps_cred_cb;
476         wps->event_cb = hostapd_wps_event_cb;
477         wps->cb_ctx = hapd;
478
479         os_memset(&cfg, 0, sizeof(cfg));
480         wps->wps_state = hapd->conf->wps_state;
481         wps->ap_setup_locked = hapd->conf->ap_setup_locked;
482         if (is_nil_uuid(hapd->conf->uuid)) {
483                 uuid_gen_mac_addr(hapd->own_addr, wps->uuid);
484                 wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC address",
485                             wps->uuid, UUID_LEN);
486         } else
487                 os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN);
488         wps->ssid_len = hapd->conf->ssid.ssid_len;
489         os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len);
490         wps->ap = 1;
491         os_memcpy(wps->dev.mac_addr, hapd->own_addr, ETH_ALEN);
492         wps->dev.device_name = hapd->conf->device_name ?
493                 os_strdup(hapd->conf->device_name) : NULL;
494         wps->dev.manufacturer = hapd->conf->manufacturer ?
495                 os_strdup(hapd->conf->manufacturer) : NULL;
496         wps->dev.model_name = hapd->conf->model_name ?
497                 os_strdup(hapd->conf->model_name) : NULL;
498         wps->dev.model_number = hapd->conf->model_number ?
499                 os_strdup(hapd->conf->model_number) : NULL;
500         wps->dev.serial_number = hapd->conf->serial_number ?
501                 os_strdup(hapd->conf->serial_number) : NULL;
502         wps->config_methods =
503                 wps_config_methods_str2bin(hapd->conf->config_methods);
504         if (hapd->conf->device_type &&
505             wps_dev_type_str2bin(hapd->conf->device_type,
506                                  wps->dev.pri_dev_type) < 0) {
507                 wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
508                 os_free(wps);
509                 return -1;
510         }
511         wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
512         wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
513                 WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
514
515         if (conf->wpa & WPA_PROTO_RSN) {
516                 if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
517                         wps->auth_types |= WPS_AUTH_WPA2PSK;
518                 if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
519                         wps->auth_types |= WPS_AUTH_WPA2;
520
521                 if (conf->rsn_pairwise & WPA_CIPHER_CCMP)
522                         wps->encr_types |= WPS_ENCR_AES;
523                 if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
524                         wps->encr_types |= WPS_ENCR_TKIP;
525         }
526
527         if (conf->wpa & WPA_PROTO_WPA) {
528                 if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
529                         wps->auth_types |= WPS_AUTH_WPAPSK;
530                 if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
531                         wps->auth_types |= WPS_AUTH_WPA;
532
533                 if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
534                         wps->encr_types |= WPS_ENCR_AES;
535                 if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
536                         wps->encr_types |= WPS_ENCR_TKIP;
537         }
538
539         if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
540                 wps->encr_types |= WPS_ENCR_NONE;
541                 wps->auth_types |= WPS_AUTH_OPEN;
542         } else if (conf->ssid.security_policy == SECURITY_STATIC_WEP) {
543                 wps->encr_types |= WPS_ENCR_WEP;
544                 if (conf->auth_algs & WPA_AUTH_ALG_OPEN)
545                         wps->auth_types |= WPS_AUTH_OPEN;
546                 if (conf->auth_algs & WPA_AUTH_ALG_SHARED)
547                         wps->auth_types |= WPS_AUTH_SHARED;
548         } else if (conf->ssid.security_policy == SECURITY_IEEE_802_1X) {
549                 wps->auth_types |= WPS_AUTH_OPEN;
550                 if (conf->default_wep_key_len)
551                         wps->encr_types |= WPS_ENCR_WEP;
552                 else
553                         wps->encr_types |= WPS_ENCR_NONE;
554         }
555
556         if (conf->ssid.wpa_psk_file) {
557                 /* Use per-device PSKs */
558         } else if (conf->ssid.wpa_passphrase) {
559                 wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase);
560                 wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
561         } else if (conf->ssid.wpa_psk) {
562                 wps->network_key = os_malloc(2 * PMK_LEN + 1);
563                 if (wps->network_key == NULL) {
564                         os_free(wps);
565                         return -1;
566                 }
567                 wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
568                                  conf->ssid.wpa_psk->psk, PMK_LEN);
569                 wps->network_key_len = 2 * PMK_LEN;
570         } else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
571                 wps->network_key = os_malloc(conf->ssid.wep.len[0]);
572                 if (wps->network_key == NULL) {
573                         os_free(wps);
574                         return -1;
575                 }
576                 os_memcpy(wps->network_key, conf->ssid.wep.key[0],
577                           conf->ssid.wep.len[0]);
578                 wps->network_key_len = conf->ssid.wep.len[0];
579         }
580
581         if (conf->ssid.wpa_psk) {
582                 os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN);
583                 wps->psk_set = 1;
584         }
585
586         if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
587                 /* Override parameters to enable security by default */
588                 wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
589                 wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
590         }
591
592         wps->ap_settings = conf->ap_settings;
593         wps->ap_settings_len = conf->ap_settings_len;
594
595         cfg.new_psk_cb = hostapd_wps_new_psk_cb;
596         cfg.set_ie_cb = hostapd_wps_set_ie_cb;
597         cfg.pin_needed_cb = hostapd_wps_pin_needed_cb;
598         cfg.reg_success_cb = hostapd_wps_reg_success_cb;
599         cfg.cb_ctx = hapd;
600         cfg.skip_cred_build = conf->skip_cred_build;
601         cfg.extra_cred = conf->extra_cred;
602         cfg.extra_cred_len = conf->extra_cred_len;
603         cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
604                 conf->skip_cred_build;
605         if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
606                 cfg.static_wep_only = 1;
607
608         wps->registrar = wps_registrar_init(wps, &cfg);
609         if (wps->registrar == NULL) {
610                 printf("Failed to initialize WPS Registrar\n");
611                 os_free(wps->network_key);
612                 os_free(wps);
613                 return -1;
614         }
615
616 #ifdef CONFIG_WPS_UPNP
617         wps->friendly_name = hapd->conf->friendly_name;
618         wps->manufacturer_url = hapd->conf->manufacturer_url;
619         wps->model_description = hapd->conf->model_description;
620         wps->model_url = hapd->conf->model_url;
621         wps->upc = hapd->conf->upc;
622
623         if (hostapd_wps_upnp_init(hapd, wps) < 0) {
624                 wpa_printf(MSG_ERROR, "Failed to initialize WPS UPnP");
625                 wps_registrar_deinit(wps->registrar);
626                 os_free(wps->network_key);
627                 os_free(wps);
628                 return -1;
629         }
630 #endif /* CONFIG_WPS_UPNP */
631
632         hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd);
633
634         hapd->wps = wps;
635
636         return 0;
637 }
638
639
640 void hostapd_deinit_wps(struct hostapd_data *hapd)
641 {
642         if (hapd->wps == NULL)
643                 return;
644 #ifdef CONFIG_WPS_UPNP
645         hostapd_wps_upnp_deinit(hapd);
646 #endif /* CONFIG_WPS_UPNP */
647         wps_registrar_deinit(hapd->wps->registrar);
648         os_free(hapd->wps->network_key);
649         wps_device_data_free(&hapd->wps->dev);
650         wpabuf_free(hapd->wps->dh_pubkey);
651         wpabuf_free(hapd->wps->dh_privkey);
652         wpabuf_free(hapd->wps->oob_conf.pubkey_hash);
653         wpabuf_free(hapd->wps->oob_conf.dev_password);
654         wps_free_pending_msgs(hapd->wps->upnp_msgs);
655         os_free(hapd->wps);
656         hapd->wps = NULL;
657         hostapd_wps_clear_ies(hapd);
658 }
659
660
661 int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
662                         const char *pin, int timeout)
663 {
664         u8 u[UUID_LEN];
665         int any = 0;
666
667         if (hapd->wps == NULL)
668                 return -1;
669         if (os_strcmp(uuid, "any") == 0)
670                 any = 1;
671         else if (uuid_str2bin(uuid, u))
672                 return -1;
673         return wps_registrar_add_pin(hapd->wps->registrar, any ? NULL : u,
674                                      (const u8 *) pin, os_strlen(pin),
675                                      timeout);
676 }
677
678
679 int hostapd_wps_button_pushed(struct hostapd_data *hapd)
680 {
681         if (hapd->wps == NULL)
682                 return -1;
683         return wps_registrar_button_pushed(hapd->wps->registrar);
684 }
685
686
687 #ifdef CONFIG_WPS_OOB
688 int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
689                           char *path, char *method, char *name)
690 {
691         struct wps_context *wps = hapd->wps;
692         struct oob_device_data *oob_dev;
693
694         oob_dev = wps_get_oob_device(device_type);
695         if (oob_dev == NULL)
696                 return -1;
697         oob_dev->device_path = path;
698         oob_dev->device_name = name;
699         wps->oob_conf.oob_method = wps_get_oob_method(method);
700
701         if (wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) {
702                 /*
703                  * Use pre-configured DH keys in order to be able to write the
704                  * key hash into the OOB file.
705                  */
706                 wpabuf_free(wps->dh_pubkey);
707                 wpabuf_free(wps->dh_privkey);
708                 wps->dh_privkey = NULL;
709                 wps->dh_pubkey = dh_init(dh_groups_get(WPS_DH_GROUP),
710                                          &wps->dh_privkey);
711                 wps->dh_pubkey = wpabuf_zeropad(wps->dh_pubkey, 192);
712                 if (wps->dh_pubkey == NULL) {
713                         wpa_printf(MSG_ERROR, "WPS: Failed to initialize "
714                                    "Diffie-Hellman handshake");
715                         return -1;
716                 }
717         }
718
719         if (wps_process_oob(wps, oob_dev, 1) < 0)
720                 goto error;
721
722         if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
723              wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
724             hostapd_wps_add_pin(hapd, "any",
725                                 wpabuf_head(wps->oob_conf.dev_password), 0) <
726             0)
727                 goto error;
728
729         return 0;
730
731 error:
732         wpabuf_free(wps->dh_pubkey);
733         wps->dh_pubkey = NULL;
734         wpabuf_free(wps->dh_privkey);
735         wps->dh_privkey = NULL;
736         return -1;
737 }
738 #endif /* CONFIG_WPS_OOB */
739
740
741 static void hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
742                                      const u8 *ie, size_t ie_len)
743 {
744         struct hostapd_data *hapd = ctx;
745         struct wpabuf *wps_ie;
746
747         if (hapd->wps == NULL)
748                 return;
749
750         wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
751         if (wps_ie == NULL)
752                 return;
753
754         if (wpabuf_len(wps_ie) > 0) {
755                 wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie);
756 #ifdef CONFIG_WPS_UPNP
757                 /* FIX: what exactly should be included in the WLANEvent?
758                  * WPS attributes? Full ProbeReq frame? */
759                 upnp_wps_device_send_wlan_event(hapd->wps_upnp, addr,
760                                                 UPNP_WPS_WLANEVENT_TYPE_PROBE,
761                                                 wps_ie);
762 #endif /* CONFIG_WPS_UPNP */
763         }
764
765         wpabuf_free(wps_ie);
766 }
767
768
769 #ifdef CONFIG_WPS_UPNP
770
771 static int hostapd_rx_req_put_wlan_response(
772         void *priv, enum upnp_wps_wlanevent_type ev_type,
773         const u8 *mac_addr, const struct wpabuf *msg,
774         enum wps_msg_type msg_type)
775 {
776         struct hostapd_data *hapd = priv;
777         struct sta_info *sta;
778         struct upnp_pending_message *p;
779
780         wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr="
781                    MACSTR, ev_type, MAC2STR(mac_addr));
782         wpa_hexdump(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage",
783                     wpabuf_head(msg), wpabuf_len(msg));
784         if (ev_type != UPNP_WPS_WLANEVENT_TYPE_EAP) {
785                 wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored unexpected "
786                            "PutWLANResponse WLANEventType %d", ev_type);
787                 return -1;
788         }
789
790         /*
791          * EAP response to ongoing to WPS Registration. Send it to EAP-WSC
792          * server implementation for delivery to the peer.
793          */
794
795         sta = ap_get_sta(hapd, mac_addr);
796         if (!sta) {
797                 /*
798                  * Workaround - Intel wsccmd uses bogus NewWLANEventMAC:
799                  * Pick STA that is in an ongoing WPS registration without
800                  * checking the MAC address.
801                  */
802                 wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found based "
803                            "on NewWLANEventMAC; try wildcard match");
804                 for (sta = hapd->sta_list; sta; sta = sta->next) {
805                         if (sta->eapol_sm && (sta->flags & WLAN_STA_WPS))
806                                 break;
807                 }
808         }
809
810         if (!sta) {
811                 wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
812                 return 0;
813         }
814
815         p = os_zalloc(sizeof(*p));
816         if (p == NULL)
817                 return -1;
818         os_memcpy(p->addr, sta->addr, ETH_ALEN);
819         p->msg = wpabuf_dup(msg);
820         p->type = msg_type;
821         p->next = hapd->wps->upnp_msgs;
822         hapd->wps->upnp_msgs = p;
823
824         return eapol_auth_eap_pending_cb(sta->eapol_sm, sta->eapol_sm->eap);
825 }
826
827
828 static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
829                                  struct wps_context *wps)
830 {
831         struct upnp_wps_device_ctx *ctx;
832
833         if (!hapd->conf->upnp_iface)
834                 return 0;
835         ctx = os_zalloc(sizeof(*ctx));
836         if (ctx == NULL)
837                 return -1;
838
839         ctx->rx_req_put_wlan_response = hostapd_rx_req_put_wlan_response;
840         if (hapd->conf->ap_pin)
841                 ctx->ap_pin = os_strdup(hapd->conf->ap_pin);
842
843         hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd);
844         if (hapd->wps_upnp == NULL) {
845                 os_free(ctx);
846                 return -1;
847         }
848         wps->wps_upnp = hapd->wps_upnp;
849
850         if (upnp_wps_device_start(hapd->wps_upnp, hapd->conf->upnp_iface)) {
851                 upnp_wps_device_deinit(hapd->wps_upnp);
852                 hapd->wps_upnp = NULL;
853                 return -1;
854         }
855
856         return 0;
857 }
858
859
860 static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd)
861 {
862         upnp_wps_device_deinit(hapd->wps_upnp);
863 }
864
865 #endif /* CONFIG_WPS_UPNP */
866
867
868 int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
869                             char *buf, size_t buflen)
870 {
871         return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen);
872 }