1214501Srpaulo/* 2214501Srpaulo * hostapd / WPS integration 3252726Srpaulo * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "utils/includes.h" 10214501Srpaulo 11214501Srpaulo#include "utils/common.h" 12214501Srpaulo#include "utils/eloop.h" 13214501Srpaulo#include "utils/uuid.h" 14214501Srpaulo#include "common/wpa_ctrl.h" 15214501Srpaulo#include "common/ieee802_11_defs.h" 16214501Srpaulo#include "common/ieee802_11_common.h" 17214501Srpaulo#include "eapol_auth/eapol_auth_sm.h" 18214501Srpaulo#include "eapol_auth/eapol_auth_sm_i.h" 19214501Srpaulo#include "wps/wps.h" 20214501Srpaulo#include "wps/wps_defs.h" 21214501Srpaulo#include "wps/wps_dev_attr.h" 22252726Srpaulo#include "wps/wps_attr_parse.h" 23214501Srpaulo#include "hostapd.h" 24214501Srpaulo#include "ap_config.h" 25252726Srpaulo#include "ap_drv_ops.h" 26214501Srpaulo#include "beacon.h" 27214501Srpaulo#include "sta_info.h" 28214501Srpaulo#include "wps_hostapd.h" 29214501Srpaulo 30214501Srpaulo 31214501Srpaulo#ifdef CONFIG_WPS_UPNP 32214501Srpaulo#include "wps/wps_upnp.h" 33214501Srpaulostatic int hostapd_wps_upnp_init(struct hostapd_data *hapd, 34214501Srpaulo struct wps_context *wps); 35214501Srpaulostatic void hostapd_wps_upnp_deinit(struct hostapd_data *hapd); 36214501Srpaulo#endif /* CONFIG_WPS_UPNP */ 37214501Srpaulo 38252726Srpaulostatic int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da, 39252726Srpaulo const u8 *bssid, 40252726Srpaulo const u8 *ie, size_t ie_len, 41252726Srpaulo int ssi_signal); 42214501Srpaulostatic void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx); 43214501Srpaulo 44214501Srpaulo 45252726Srpaulostruct wps_for_each_data { 46252726Srpaulo int (*func)(struct hostapd_data *h, void *ctx); 47252726Srpaulo void *ctx; 48252726Srpaulo}; 49252726Srpaulo 50252726Srpaulo 51252726Srpaulostatic int wps_for_each(struct hostapd_iface *iface, void *ctx) 52252726Srpaulo{ 53252726Srpaulo struct wps_for_each_data *data = ctx; 54252726Srpaulo size_t j; 55252726Srpaulo 56252726Srpaulo if (iface == NULL) 57252726Srpaulo return 0; 58252726Srpaulo for (j = 0; j < iface->num_bss; j++) { 59252726Srpaulo struct hostapd_data *hapd = iface->bss[j]; 60252726Srpaulo int ret = data->func(hapd, data->ctx); 61252726Srpaulo if (ret) 62252726Srpaulo return ret; 63252726Srpaulo } 64252726Srpaulo 65252726Srpaulo return 0; 66252726Srpaulo} 67252726Srpaulo 68252726Srpaulo 69252726Srpaulostatic int hostapd_wps_for_each(struct hostapd_data *hapd, 70252726Srpaulo int (*func)(struct hostapd_data *h, void *ctx), 71252726Srpaulo void *ctx) 72252726Srpaulo{ 73252726Srpaulo struct hostapd_iface *iface = hapd->iface; 74252726Srpaulo struct wps_for_each_data data; 75252726Srpaulo data.func = func; 76252726Srpaulo data.ctx = ctx; 77252726Srpaulo if (iface->interfaces == NULL || 78252726Srpaulo iface->interfaces->for_each_interface == NULL) 79252726Srpaulo return wps_for_each(iface, &data); 80252726Srpaulo return iface->interfaces->for_each_interface(iface->interfaces, 81252726Srpaulo wps_for_each, &data); 82252726Srpaulo} 83252726Srpaulo 84252726Srpaulo 85214501Srpaulostatic int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk, 86214501Srpaulo size_t psk_len) 87214501Srpaulo{ 88214501Srpaulo struct hostapd_data *hapd = ctx; 89214501Srpaulo struct hostapd_wpa_psk *p; 90214501Srpaulo struct hostapd_ssid *ssid = &hapd->conf->ssid; 91214501Srpaulo 92214501Srpaulo wpa_printf(MSG_DEBUG, "Received new WPA/WPA2-PSK from WPS for STA " 93214501Srpaulo MACSTR, MAC2STR(mac_addr)); 94214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len); 95214501Srpaulo 96214501Srpaulo if (psk_len != PMK_LEN) { 97214501Srpaulo wpa_printf(MSG_DEBUG, "Unexpected PSK length %lu", 98214501Srpaulo (unsigned long) psk_len); 99214501Srpaulo return -1; 100214501Srpaulo } 101214501Srpaulo 102214501Srpaulo /* Add the new PSK to runtime PSK list */ 103214501Srpaulo p = os_zalloc(sizeof(*p)); 104214501Srpaulo if (p == NULL) 105214501Srpaulo return -1; 106214501Srpaulo os_memcpy(p->addr, mac_addr, ETH_ALEN); 107214501Srpaulo os_memcpy(p->psk, psk, PMK_LEN); 108214501Srpaulo 109214501Srpaulo p->next = ssid->wpa_psk; 110214501Srpaulo ssid->wpa_psk = p; 111214501Srpaulo 112214501Srpaulo if (ssid->wpa_psk_file) { 113214501Srpaulo FILE *f; 114214501Srpaulo char hex[PMK_LEN * 2 + 1]; 115214501Srpaulo /* Add the new PSK to PSK list file */ 116214501Srpaulo f = fopen(ssid->wpa_psk_file, "a"); 117214501Srpaulo if (f == NULL) { 118214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to add the PSK to " 119214501Srpaulo "'%s'", ssid->wpa_psk_file); 120214501Srpaulo return -1; 121214501Srpaulo } 122214501Srpaulo 123214501Srpaulo wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len); 124214501Srpaulo fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex); 125214501Srpaulo fclose(f); 126214501Srpaulo } 127214501Srpaulo 128214501Srpaulo return 0; 129214501Srpaulo} 130214501Srpaulo 131214501Srpaulo 132214501Srpaulostatic int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie, 133214501Srpaulo struct wpabuf *probe_resp_ie) 134214501Srpaulo{ 135214501Srpaulo struct hostapd_data *hapd = ctx; 136214501Srpaulo wpabuf_free(hapd->wps_beacon_ie); 137214501Srpaulo hapd->wps_beacon_ie = beacon_ie; 138214501Srpaulo wpabuf_free(hapd->wps_probe_resp_ie); 139214501Srpaulo hapd->wps_probe_resp_ie = probe_resp_ie; 140252726Srpaulo if (hapd->beacon_set_done) 141252726Srpaulo ieee802_11_set_beacon(hapd); 142252726Srpaulo return hostapd_set_ap_wps_ie(hapd); 143214501Srpaulo} 144214501Srpaulo 145214501Srpaulo 146214501Srpaulostatic void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e, 147214501Srpaulo const struct wps_device_data *dev) 148214501Srpaulo{ 149214501Srpaulo struct hostapd_data *hapd = ctx; 150214501Srpaulo char uuid[40], txt[400]; 151214501Srpaulo int len; 152214501Srpaulo char devtype[WPS_DEV_TYPE_BUFSIZE]; 153214501Srpaulo if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) 154214501Srpaulo return; 155214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: PIN needed for E-UUID %s", uuid); 156214501Srpaulo len = os_snprintf(txt, sizeof(txt), WPS_EVENT_PIN_NEEDED 157214501Srpaulo "%s " MACSTR " [%s|%s|%s|%s|%s|%s]", 158214501Srpaulo uuid, MAC2STR(dev->mac_addr), dev->device_name, 159214501Srpaulo dev->manufacturer, dev->model_name, 160214501Srpaulo dev->model_number, dev->serial_number, 161214501Srpaulo wps_dev_type_bin2str(dev->pri_dev_type, devtype, 162214501Srpaulo sizeof(devtype))); 163214501Srpaulo if (len > 0 && len < (int) sizeof(txt)) 164214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt); 165214501Srpaulo 166214501Srpaulo if (hapd->conf->wps_pin_requests) { 167214501Srpaulo FILE *f; 168214501Srpaulo struct os_time t; 169214501Srpaulo f = fopen(hapd->conf->wps_pin_requests, "a"); 170214501Srpaulo if (f == NULL) 171214501Srpaulo return; 172214501Srpaulo os_get_time(&t); 173214501Srpaulo fprintf(f, "%ld\t%s\t" MACSTR "\t%s\t%s\t%s\t%s\t%s" 174214501Srpaulo "\t%s\n", 175214501Srpaulo t.sec, uuid, MAC2STR(dev->mac_addr), dev->device_name, 176214501Srpaulo dev->manufacturer, dev->model_name, dev->model_number, 177214501Srpaulo dev->serial_number, 178214501Srpaulo wps_dev_type_bin2str(dev->pri_dev_type, devtype, 179214501Srpaulo sizeof(devtype))); 180214501Srpaulo fclose(f); 181214501Srpaulo } 182214501Srpaulo} 183214501Srpaulo 184214501Srpaulo 185252726Srpaulostruct wps_stop_reg_data { 186252726Srpaulo struct hostapd_data *current_hapd; 187252726Srpaulo const u8 *uuid_e; 188252726Srpaulo const u8 *dev_pw; 189252726Srpaulo size_t dev_pw_len; 190252726Srpaulo}; 191252726Srpaulo 192252726Srpaulostatic int wps_stop_registrar(struct hostapd_data *hapd, void *ctx) 193252726Srpaulo{ 194252726Srpaulo struct wps_stop_reg_data *data = ctx; 195252726Srpaulo if (hapd != data->current_hapd && hapd->wps != NULL) 196252726Srpaulo wps_registrar_complete(hapd->wps->registrar, data->uuid_e, 197252726Srpaulo data->dev_pw, data->dev_pw_len); 198252726Srpaulo return 0; 199252726Srpaulo} 200252726Srpaulo 201252726Srpaulo 202214501Srpaulostatic void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr, 203252726Srpaulo const u8 *uuid_e, const u8 *dev_pw, 204252726Srpaulo size_t dev_pw_len) 205214501Srpaulo{ 206214501Srpaulo struct hostapd_data *hapd = ctx; 207214501Srpaulo char uuid[40]; 208252726Srpaulo struct wps_stop_reg_data data; 209214501Srpaulo if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) 210214501Srpaulo return; 211214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s", 212214501Srpaulo MAC2STR(mac_addr), uuid); 213214501Srpaulo if (hapd->wps_reg_success_cb) 214214501Srpaulo hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx, 215214501Srpaulo mac_addr, uuid_e); 216252726Srpaulo data.current_hapd = hapd; 217252726Srpaulo data.uuid_e = uuid_e; 218252726Srpaulo data.dev_pw = dev_pw; 219252726Srpaulo data.dev_pw_len = dev_pw_len; 220252726Srpaulo hostapd_wps_for_each(hapd, wps_stop_registrar, &data); 221214501Srpaulo} 222214501Srpaulo 223214501Srpaulo 224214501Srpaulostatic void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr, 225214501Srpaulo const u8 *uuid_e, 226214501Srpaulo const u8 *pri_dev_type, 227214501Srpaulo u16 config_methods, 228214501Srpaulo u16 dev_password_id, u8 request_type, 229214501Srpaulo const char *dev_name) 230214501Srpaulo{ 231214501Srpaulo struct hostapd_data *hapd = ctx; 232214501Srpaulo char uuid[40]; 233214501Srpaulo char devtype[WPS_DEV_TYPE_BUFSIZE]; 234214501Srpaulo if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) 235214501Srpaulo return; 236214501Srpaulo if (dev_name == NULL) 237214501Srpaulo dev_name = ""; 238214501Srpaulo wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ENROLLEE_SEEN MACSTR 239214501Srpaulo " %s %s 0x%x %u %u [%s]", 240214501Srpaulo MAC2STR(addr), uuid, 241214501Srpaulo wps_dev_type_bin2str(pri_dev_type, devtype, 242214501Srpaulo sizeof(devtype)), 243214501Srpaulo config_methods, dev_password_id, request_type, dev_name); 244214501Srpaulo} 245214501Srpaulo 246214501Srpaulo 247214501Srpaulostatic int str_starts(const char *str, const char *start) 248214501Srpaulo{ 249214501Srpaulo return os_strncmp(str, start, os_strlen(start)) == 0; 250214501Srpaulo} 251214501Srpaulo 252214501Srpaulo 253214501Srpaulostatic void wps_reload_config(void *eloop_data, void *user_ctx) 254214501Srpaulo{ 255214501Srpaulo struct hostapd_iface *iface = eloop_data; 256214501Srpaulo 257214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Reload configuration data"); 258252726Srpaulo if (iface->interfaces == NULL || 259252726Srpaulo iface->interfaces->reload_config(iface) < 0) { 260214501Srpaulo wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated " 261214501Srpaulo "configuration"); 262214501Srpaulo } 263214501Srpaulo} 264214501Srpaulo 265214501Srpaulo 266252726Srpaulostatic void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr, 267252726Srpaulo size_t attr_len) 268214501Srpaulo{ 269252726Srpaulo size_t blen = attr_len * 2 + 1; 270252726Srpaulo char *buf = os_malloc(blen); 271252726Srpaulo if (buf) { 272252726Srpaulo wpa_snprintf_hex(buf, blen, attr, attr_len); 273252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, 274252726Srpaulo WPS_EVENT_NEW_AP_SETTINGS "%s", buf); 275252726Srpaulo os_free(buf); 276252726Srpaulo } 277252726Srpaulo} 278252726Srpaulo 279252726Srpaulo 280252726Srpaulostatic int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx) 281252726Srpaulo{ 282252726Srpaulo const struct wps_credential *cred = ctx; 283214501Srpaulo FILE *oconf, *nconf; 284214501Srpaulo size_t len, i; 285214501Srpaulo char *tmp_fname; 286214501Srpaulo char buf[1024]; 287214501Srpaulo int multi_bss; 288214501Srpaulo int wpa; 289214501Srpaulo 290252726Srpaulo if (hapd->wps == NULL) 291252726Srpaulo return 0; 292252726Srpaulo 293214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute", 294214501Srpaulo cred->cred_attr, cred->cred_attr_len); 295214501Srpaulo 296214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Received new AP Settings"); 297214501Srpaulo wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len); 298214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x", 299214501Srpaulo cred->auth_type); 300214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type); 301214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx); 302214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", 303214501Srpaulo cred->key, cred->key_len); 304214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, 305214501Srpaulo MAC2STR(cred->mac_addr)); 306214501Srpaulo 307214501Srpaulo if ((hapd->conf->wps_cred_processing == 1 || 308214501Srpaulo hapd->conf->wps_cred_processing == 2) && cred->cred_attr) { 309252726Srpaulo hapd_new_ap_event(hapd, cred->cred_attr, cred->cred_attr_len); 310252726Srpaulo } else if (hapd->conf->wps_cred_processing == 1 || 311252726Srpaulo hapd->conf->wps_cred_processing == 2) { 312252726Srpaulo struct wpabuf *attr; 313252726Srpaulo attr = wpabuf_alloc(200); 314252726Srpaulo if (attr && wps_build_credential_wrap(attr, cred) == 0) 315252726Srpaulo hapd_new_ap_event(hapd, wpabuf_head_u8(attr), 316252726Srpaulo wpabuf_len(attr)); 317252726Srpaulo wpabuf_free(attr); 318214501Srpaulo } else 319214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS); 320214501Srpaulo 321214501Srpaulo if (hapd->conf->wps_cred_processing == 1) 322214501Srpaulo return 0; 323214501Srpaulo 324214501Srpaulo os_memcpy(hapd->wps->ssid, cred->ssid, cred->ssid_len); 325214501Srpaulo hapd->wps->ssid_len = cred->ssid_len; 326214501Srpaulo hapd->wps->encr_types = cred->encr_type; 327214501Srpaulo hapd->wps->auth_types = cred->auth_type; 328214501Srpaulo if (cred->key_len == 0) { 329214501Srpaulo os_free(hapd->wps->network_key); 330214501Srpaulo hapd->wps->network_key = NULL; 331214501Srpaulo hapd->wps->network_key_len = 0; 332214501Srpaulo } else { 333214501Srpaulo if (hapd->wps->network_key == NULL || 334214501Srpaulo hapd->wps->network_key_len < cred->key_len) { 335214501Srpaulo hapd->wps->network_key_len = 0; 336214501Srpaulo os_free(hapd->wps->network_key); 337214501Srpaulo hapd->wps->network_key = os_malloc(cred->key_len); 338214501Srpaulo if (hapd->wps->network_key == NULL) 339214501Srpaulo return -1; 340214501Srpaulo } 341214501Srpaulo hapd->wps->network_key_len = cred->key_len; 342214501Srpaulo os_memcpy(hapd->wps->network_key, cred->key, cred->key_len); 343214501Srpaulo } 344214501Srpaulo hapd->wps->wps_state = WPS_STATE_CONFIGURED; 345214501Srpaulo 346252726Srpaulo if (hapd->iface->config_fname == NULL) 347252726Srpaulo return 0; 348214501Srpaulo len = os_strlen(hapd->iface->config_fname) + 5; 349214501Srpaulo tmp_fname = os_malloc(len); 350214501Srpaulo if (tmp_fname == NULL) 351214501Srpaulo return -1; 352214501Srpaulo os_snprintf(tmp_fname, len, "%s-new", hapd->iface->config_fname); 353214501Srpaulo 354214501Srpaulo oconf = fopen(hapd->iface->config_fname, "r"); 355214501Srpaulo if (oconf == NULL) { 356214501Srpaulo wpa_printf(MSG_WARNING, "WPS: Could not open current " 357214501Srpaulo "configuration file"); 358214501Srpaulo os_free(tmp_fname); 359214501Srpaulo return -1; 360214501Srpaulo } 361214501Srpaulo 362214501Srpaulo nconf = fopen(tmp_fname, "w"); 363214501Srpaulo if (nconf == NULL) { 364214501Srpaulo wpa_printf(MSG_WARNING, "WPS: Could not write updated " 365214501Srpaulo "configuration file"); 366214501Srpaulo os_free(tmp_fname); 367214501Srpaulo fclose(oconf); 368214501Srpaulo return -1; 369214501Srpaulo } 370214501Srpaulo 371214501Srpaulo fprintf(nconf, "# WPS configuration - START\n"); 372214501Srpaulo 373214501Srpaulo fprintf(nconf, "wps_state=2\n"); 374214501Srpaulo 375252726Srpaulo if (is_hex(cred->ssid, cred->ssid_len)) { 376252726Srpaulo fprintf(nconf, "ssid2="); 377252726Srpaulo for (i = 0; i < cred->ssid_len; i++) 378252726Srpaulo fprintf(nconf, "%02x", cred->ssid[i]); 379252726Srpaulo fprintf(nconf, "\n"); 380252726Srpaulo } else { 381252726Srpaulo fprintf(nconf, "ssid="); 382252726Srpaulo for (i = 0; i < cred->ssid_len; i++) 383252726Srpaulo fputc(cred->ssid[i], nconf); 384252726Srpaulo fprintf(nconf, "\n"); 385252726Srpaulo } 386214501Srpaulo 387214501Srpaulo if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) && 388214501Srpaulo (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))) 389214501Srpaulo wpa = 3; 390214501Srpaulo else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) 391214501Srpaulo wpa = 2; 392214501Srpaulo else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)) 393214501Srpaulo wpa = 1; 394214501Srpaulo else 395214501Srpaulo wpa = 0; 396214501Srpaulo 397214501Srpaulo if (wpa) { 398214501Srpaulo char *prefix; 399214501Srpaulo fprintf(nconf, "wpa=%d\n", wpa); 400214501Srpaulo 401214501Srpaulo fprintf(nconf, "wpa_key_mgmt="); 402214501Srpaulo prefix = ""; 403214501Srpaulo if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA)) { 404214501Srpaulo fprintf(nconf, "WPA-EAP"); 405214501Srpaulo prefix = " "; 406214501Srpaulo } 407214501Srpaulo if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) 408214501Srpaulo fprintf(nconf, "%sWPA-PSK", prefix); 409214501Srpaulo fprintf(nconf, "\n"); 410214501Srpaulo 411214501Srpaulo fprintf(nconf, "wpa_pairwise="); 412214501Srpaulo prefix = ""; 413214501Srpaulo if (cred->encr_type & WPS_ENCR_AES) { 414214501Srpaulo fprintf(nconf, "CCMP"); 415214501Srpaulo prefix = " "; 416214501Srpaulo } 417214501Srpaulo if (cred->encr_type & WPS_ENCR_TKIP) { 418214501Srpaulo fprintf(nconf, "%sTKIP", prefix); 419214501Srpaulo } 420214501Srpaulo fprintf(nconf, "\n"); 421214501Srpaulo 422214501Srpaulo if (cred->key_len >= 8 && cred->key_len < 64) { 423214501Srpaulo fprintf(nconf, "wpa_passphrase="); 424214501Srpaulo for (i = 0; i < cred->key_len; i++) 425214501Srpaulo fputc(cred->key[i], nconf); 426214501Srpaulo fprintf(nconf, "\n"); 427214501Srpaulo } else if (cred->key_len == 64) { 428214501Srpaulo fprintf(nconf, "wpa_psk="); 429214501Srpaulo for (i = 0; i < cred->key_len; i++) 430214501Srpaulo fputc(cred->key[i], nconf); 431214501Srpaulo fprintf(nconf, "\n"); 432214501Srpaulo } else { 433214501Srpaulo wpa_printf(MSG_WARNING, "WPS: Invalid key length %lu " 434214501Srpaulo "for WPA/WPA2", 435214501Srpaulo (unsigned long) cred->key_len); 436214501Srpaulo } 437214501Srpaulo 438214501Srpaulo fprintf(nconf, "auth_algs=1\n"); 439214501Srpaulo } else { 440214501Srpaulo if ((cred->auth_type & WPS_AUTH_OPEN) && 441214501Srpaulo (cred->auth_type & WPS_AUTH_SHARED)) 442214501Srpaulo fprintf(nconf, "auth_algs=3\n"); 443214501Srpaulo else if (cred->auth_type & WPS_AUTH_SHARED) 444214501Srpaulo fprintf(nconf, "auth_algs=2\n"); 445214501Srpaulo else 446214501Srpaulo fprintf(nconf, "auth_algs=1\n"); 447214501Srpaulo 448214501Srpaulo if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx <= 4) { 449214501Srpaulo int key_idx = cred->key_idx; 450214501Srpaulo if (key_idx) 451214501Srpaulo key_idx--; 452214501Srpaulo fprintf(nconf, "wep_default_key=%d\n", key_idx); 453214501Srpaulo fprintf(nconf, "wep_key%d=", key_idx); 454214501Srpaulo if (cred->key_len == 10 || cred->key_len == 26) { 455214501Srpaulo /* WEP key as a hex string */ 456214501Srpaulo for (i = 0; i < cred->key_len; i++) 457214501Srpaulo fputc(cred->key[i], nconf); 458214501Srpaulo } else { 459214501Srpaulo /* Raw WEP key; convert to hex */ 460214501Srpaulo for (i = 0; i < cred->key_len; i++) 461214501Srpaulo fprintf(nconf, "%02x", cred->key[i]); 462214501Srpaulo } 463214501Srpaulo fprintf(nconf, "\n"); 464214501Srpaulo } 465214501Srpaulo } 466214501Srpaulo 467214501Srpaulo fprintf(nconf, "# WPS configuration - END\n"); 468214501Srpaulo 469214501Srpaulo multi_bss = 0; 470214501Srpaulo while (fgets(buf, sizeof(buf), oconf)) { 471214501Srpaulo if (os_strncmp(buf, "bss=", 4) == 0) 472214501Srpaulo multi_bss = 1; 473214501Srpaulo if (!multi_bss && 474214501Srpaulo (str_starts(buf, "ssid=") || 475252726Srpaulo str_starts(buf, "ssid2=") || 476214501Srpaulo str_starts(buf, "auth_algs=") || 477252726Srpaulo str_starts(buf, "wep_default_key=") || 478252726Srpaulo str_starts(buf, "wep_key") || 479214501Srpaulo str_starts(buf, "wps_state=") || 480214501Srpaulo str_starts(buf, "wpa=") || 481214501Srpaulo str_starts(buf, "wpa_psk=") || 482214501Srpaulo str_starts(buf, "wpa_pairwise=") || 483214501Srpaulo str_starts(buf, "rsn_pairwise=") || 484214501Srpaulo str_starts(buf, "wpa_key_mgmt=") || 485214501Srpaulo str_starts(buf, "wpa_passphrase="))) { 486214501Srpaulo fprintf(nconf, "#WPS# %s", buf); 487214501Srpaulo } else 488214501Srpaulo fprintf(nconf, "%s", buf); 489214501Srpaulo } 490214501Srpaulo 491214501Srpaulo fclose(nconf); 492214501Srpaulo fclose(oconf); 493214501Srpaulo 494214501Srpaulo if (rename(tmp_fname, hapd->iface->config_fname) < 0) { 495214501Srpaulo wpa_printf(MSG_WARNING, "WPS: Failed to rename the updated " 496214501Srpaulo "configuration file: %s", strerror(errno)); 497214501Srpaulo os_free(tmp_fname); 498214501Srpaulo return -1; 499214501Srpaulo } 500214501Srpaulo 501214501Srpaulo os_free(tmp_fname); 502214501Srpaulo 503214501Srpaulo /* Schedule configuration reload after short period of time to allow 504214501Srpaulo * EAP-WSC to be finished. 505214501Srpaulo */ 506214501Srpaulo eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface, 507214501Srpaulo NULL); 508214501Srpaulo 509214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: AP configuration updated"); 510214501Srpaulo 511214501Srpaulo return 0; 512214501Srpaulo} 513214501Srpaulo 514214501Srpaulo 515252726Srpaulostatic int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred) 516252726Srpaulo{ 517252726Srpaulo struct hostapd_data *hapd = ctx; 518252726Srpaulo return hostapd_wps_for_each(hapd, hapd_wps_cred_cb, (void *) cred); 519252726Srpaulo} 520252726Srpaulo 521252726Srpaulo 522214501Srpaulostatic void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx) 523214501Srpaulo{ 524214501Srpaulo struct hostapd_data *hapd = eloop_data; 525214501Srpaulo 526214501Srpaulo if (hapd->conf->ap_setup_locked) 527214501Srpaulo return; 528252726Srpaulo if (hapd->ap_pin_failures_consecutive >= 10) 529252726Srpaulo return; 530214501Srpaulo 531214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Re-enable AP PIN"); 532214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED); 533214501Srpaulo hapd->wps->ap_setup_locked = 0; 534214501Srpaulo wps_registrar_update_ie(hapd->wps->registrar); 535214501Srpaulo} 536214501Srpaulo 537214501Srpaulo 538252726Srpaulostatic int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx) 539214501Srpaulo{ 540252726Srpaulo struct wps_event_pwd_auth_fail *data = ctx; 541214501Srpaulo 542252726Srpaulo if (!data->enrollee || hapd->conf->ap_pin == NULL || hapd->wps == NULL) 543252726Srpaulo return 0; 544252726Srpaulo 545214501Srpaulo /* 546214501Srpaulo * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup 547214501Srpaulo * for some time if this happens multiple times to slow down brute 548214501Srpaulo * force attacks. 549214501Srpaulo */ 550214501Srpaulo hapd->ap_pin_failures++; 551252726Srpaulo hapd->ap_pin_failures_consecutive++; 552252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u " 553252726Srpaulo "(%u consecutive)", 554252726Srpaulo hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive); 555214501Srpaulo if (hapd->ap_pin_failures < 3) 556252726Srpaulo return 0; 557214501Srpaulo 558214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED); 559214501Srpaulo hapd->wps->ap_setup_locked = 1; 560214501Srpaulo 561214501Srpaulo wps_registrar_update_ie(hapd->wps->registrar); 562214501Srpaulo 563252726Srpaulo if (!hapd->conf->ap_setup_locked && 564252726Srpaulo hapd->ap_pin_failures_consecutive >= 10) { 565252726Srpaulo /* 566252726Srpaulo * In indefinite lockdown - disable automatic AP PIN 567252726Srpaulo * reenablement. 568252726Srpaulo */ 569252726Srpaulo eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); 570252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: AP PIN disabled indefinitely"); 571252726Srpaulo } else if (!hapd->conf->ap_setup_locked) { 572214501Srpaulo if (hapd->ap_pin_lockout_time == 0) 573214501Srpaulo hapd->ap_pin_lockout_time = 60; 574214501Srpaulo else if (hapd->ap_pin_lockout_time < 365 * 24 * 60 * 60 && 575214501Srpaulo (hapd->ap_pin_failures % 3) == 0) 576214501Srpaulo hapd->ap_pin_lockout_time *= 2; 577214501Srpaulo 578214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN for %u seconds", 579214501Srpaulo hapd->ap_pin_lockout_time); 580214501Srpaulo eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); 581214501Srpaulo eloop_register_timeout(hapd->ap_pin_lockout_time, 0, 582214501Srpaulo hostapd_wps_reenable_ap_pin, hapd, 583214501Srpaulo NULL); 584214501Srpaulo } 585214501Srpaulo 586252726Srpaulo return 0; 587214501Srpaulo} 588214501Srpaulo 589214501Srpaulo 590252726Srpaulostatic void hostapd_pwd_auth_fail(struct hostapd_data *hapd, 591252726Srpaulo struct wps_event_pwd_auth_fail *data) 592252726Srpaulo{ 593252726Srpaulo hostapd_wps_for_each(hapd, wps_pwd_auth_fail, data); 594252726Srpaulo} 595252726Srpaulo 596252726Srpaulo 597252726Srpaulostatic int wps_ap_pin_success(struct hostapd_data *hapd, void *ctx) 598252726Srpaulo{ 599252726Srpaulo if (hapd->conf->ap_pin == NULL || hapd->wps == NULL) 600252726Srpaulo return 0; 601252726Srpaulo 602252726Srpaulo if (hapd->ap_pin_failures_consecutive == 0) 603252726Srpaulo return 0; 604252726Srpaulo 605252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Clear consecutive AP PIN failure counter " 606252726Srpaulo "- total validation failures %u (%u consecutive)", 607252726Srpaulo hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive); 608252726Srpaulo hapd->ap_pin_failures_consecutive = 0; 609252726Srpaulo 610252726Srpaulo return 0; 611252726Srpaulo} 612252726Srpaulo 613252726Srpaulo 614252726Srpaulostatic void hostapd_wps_ap_pin_success(struct hostapd_data *hapd) 615252726Srpaulo{ 616252726Srpaulo hostapd_wps_for_each(hapd, wps_ap_pin_success, NULL); 617252726Srpaulo} 618252726Srpaulo 619252726Srpaulo 620252726Srpaulostatic const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = { 621252726Srpaulo "No Error", /* WPS_EI_NO_ERROR */ 622252726Srpaulo "TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */ 623252726Srpaulo "WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */ 624252726Srpaulo}; 625252726Srpaulo 626252726Srpaulostatic void hostapd_wps_event_fail(struct hostapd_data *hapd, 627252726Srpaulo struct wps_event_fail *fail) 628252726Srpaulo{ 629252726Srpaulo if (fail->error_indication > 0 && 630252726Srpaulo fail->error_indication < NUM_WPS_EI_VALUES) { 631252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, 632252726Srpaulo WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)", 633252726Srpaulo fail->msg, fail->config_error, fail->error_indication, 634252726Srpaulo wps_event_fail_reason[fail->error_indication]); 635252726Srpaulo } else { 636252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, 637252726Srpaulo WPS_EVENT_FAIL "msg=%d config_error=%d", 638252726Srpaulo fail->msg, fail->config_error); 639252726Srpaulo } 640252726Srpaulo} 641252726Srpaulo 642252726Srpaulo 643214501Srpaulostatic void hostapd_wps_event_cb(void *ctx, enum wps_event event, 644214501Srpaulo union wps_event_data *data) 645214501Srpaulo{ 646214501Srpaulo struct hostapd_data *hapd = ctx; 647214501Srpaulo 648252726Srpaulo switch (event) { 649252726Srpaulo case WPS_EV_M2D: 650252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_M2D); 651252726Srpaulo break; 652252726Srpaulo case WPS_EV_FAIL: 653252726Srpaulo hostapd_wps_event_fail(hapd, &data->fail); 654252726Srpaulo break; 655252726Srpaulo case WPS_EV_SUCCESS: 656252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS); 657252726Srpaulo break; 658252726Srpaulo case WPS_EV_PWD_AUTH_FAIL: 659214501Srpaulo hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail); 660252726Srpaulo break; 661252726Srpaulo case WPS_EV_PBC_OVERLAP: 662252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP); 663252726Srpaulo break; 664252726Srpaulo case WPS_EV_PBC_TIMEOUT: 665252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT); 666252726Srpaulo break; 667252726Srpaulo case WPS_EV_ER_AP_ADD: 668252726Srpaulo break; 669252726Srpaulo case WPS_EV_ER_AP_REMOVE: 670252726Srpaulo break; 671252726Srpaulo case WPS_EV_ER_ENROLLEE_ADD: 672252726Srpaulo break; 673252726Srpaulo case WPS_EV_ER_ENROLLEE_REMOVE: 674252726Srpaulo break; 675252726Srpaulo case WPS_EV_ER_AP_SETTINGS: 676252726Srpaulo break; 677252726Srpaulo case WPS_EV_ER_SET_SELECTED_REGISTRAR: 678252726Srpaulo break; 679252726Srpaulo case WPS_EV_AP_PIN_SUCCESS: 680252726Srpaulo hostapd_wps_ap_pin_success(hapd); 681252726Srpaulo break; 682252726Srpaulo } 683252726Srpaulo if (hapd->wps_event_cb) 684252726Srpaulo hapd->wps_event_cb(hapd->wps_event_cb_ctx, event, data); 685214501Srpaulo} 686214501Srpaulo 687214501Srpaulo 688214501Srpaulostatic void hostapd_wps_clear_ies(struct hostapd_data *hapd) 689214501Srpaulo{ 690214501Srpaulo wpabuf_free(hapd->wps_beacon_ie); 691214501Srpaulo hapd->wps_beacon_ie = NULL; 692214501Srpaulo 693214501Srpaulo wpabuf_free(hapd->wps_probe_resp_ie); 694214501Srpaulo hapd->wps_probe_resp_ie = NULL; 695214501Srpaulo 696252726Srpaulo hostapd_set_ap_wps_ie(hapd); 697214501Srpaulo} 698214501Srpaulo 699214501Srpaulo 700252726Srpaulostatic int get_uuid_cb(struct hostapd_iface *iface, void *ctx) 701252726Srpaulo{ 702252726Srpaulo const u8 **uuid = ctx; 703252726Srpaulo size_t j; 704252726Srpaulo 705252726Srpaulo if (iface == NULL) 706252726Srpaulo return 0; 707252726Srpaulo for (j = 0; j < iface->num_bss; j++) { 708252726Srpaulo struct hostapd_data *hapd = iface->bss[j]; 709252726Srpaulo if (hapd->wps && !is_nil_uuid(hapd->wps->uuid)) { 710252726Srpaulo *uuid = hapd->wps->uuid; 711252726Srpaulo return 1; 712252726Srpaulo } 713252726Srpaulo } 714252726Srpaulo 715252726Srpaulo return 0; 716252726Srpaulo} 717252726Srpaulo 718252726Srpaulo 719252726Srpaulostatic const u8 * get_own_uuid(struct hostapd_iface *iface) 720252726Srpaulo{ 721252726Srpaulo const u8 *uuid; 722252726Srpaulo if (iface->interfaces == NULL || 723252726Srpaulo iface->interfaces->for_each_interface == NULL) 724252726Srpaulo return NULL; 725252726Srpaulo uuid = NULL; 726252726Srpaulo iface->interfaces->for_each_interface(iface->interfaces, get_uuid_cb, 727252726Srpaulo &uuid); 728252726Srpaulo return uuid; 729252726Srpaulo} 730252726Srpaulo 731252726Srpaulo 732252726Srpaulostatic int count_interface_cb(struct hostapd_iface *iface, void *ctx) 733252726Srpaulo{ 734252726Srpaulo int *count= ctx; 735252726Srpaulo (*count)++; 736252726Srpaulo return 0; 737252726Srpaulo} 738252726Srpaulo 739252726Srpaulo 740252726Srpaulostatic int interface_count(struct hostapd_iface *iface) 741252726Srpaulo{ 742252726Srpaulo int count = 0; 743252726Srpaulo if (iface->interfaces == NULL || 744252726Srpaulo iface->interfaces->for_each_interface == NULL) 745252726Srpaulo return 0; 746252726Srpaulo iface->interfaces->for_each_interface(iface->interfaces, 747252726Srpaulo count_interface_cb, &count); 748252726Srpaulo return count; 749252726Srpaulo} 750252726Srpaulo 751252726Srpaulo 752252726Srpaulostatic int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd, 753252726Srpaulo struct wps_context *wps) 754252726Srpaulo{ 755252726Srpaulo int i; 756252726Srpaulo 757252726Srpaulo for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { 758252726Srpaulo wpabuf_free(wps->dev.vendor_ext[i]); 759252726Srpaulo wps->dev.vendor_ext[i] = NULL; 760252726Srpaulo 761252726Srpaulo if (hapd->conf->wps_vendor_ext[i] == NULL) 762252726Srpaulo continue; 763252726Srpaulo 764252726Srpaulo wps->dev.vendor_ext[i] = 765252726Srpaulo wpabuf_dup(hapd->conf->wps_vendor_ext[i]); 766252726Srpaulo if (wps->dev.vendor_ext[i] == NULL) { 767252726Srpaulo while (--i >= 0) 768252726Srpaulo wpabuf_free(wps->dev.vendor_ext[i]); 769252726Srpaulo return -1; 770252726Srpaulo } 771252726Srpaulo } 772252726Srpaulo 773252726Srpaulo return 0; 774252726Srpaulo} 775252726Srpaulo 776252726Srpaulo 777214501Srpauloint hostapd_init_wps(struct hostapd_data *hapd, 778214501Srpaulo struct hostapd_bss_config *conf) 779214501Srpaulo{ 780214501Srpaulo struct wps_context *wps; 781214501Srpaulo struct wps_registrar_config cfg; 782214501Srpaulo 783214501Srpaulo if (conf->wps_state == 0) { 784214501Srpaulo hostapd_wps_clear_ies(hapd); 785214501Srpaulo return 0; 786214501Srpaulo } 787214501Srpaulo 788214501Srpaulo wps = os_zalloc(sizeof(*wps)); 789214501Srpaulo if (wps == NULL) 790214501Srpaulo return -1; 791214501Srpaulo 792214501Srpaulo wps->cred_cb = hostapd_wps_cred_cb; 793214501Srpaulo wps->event_cb = hostapd_wps_event_cb; 794214501Srpaulo wps->cb_ctx = hapd; 795214501Srpaulo 796214501Srpaulo os_memset(&cfg, 0, sizeof(cfg)); 797214501Srpaulo wps->wps_state = hapd->conf->wps_state; 798214501Srpaulo wps->ap_setup_locked = hapd->conf->ap_setup_locked; 799214501Srpaulo if (is_nil_uuid(hapd->conf->uuid)) { 800252726Srpaulo const u8 *uuid; 801252726Srpaulo uuid = get_own_uuid(hapd->iface); 802252726Srpaulo if (uuid) { 803252726Srpaulo os_memcpy(wps->uuid, uuid, UUID_LEN); 804252726Srpaulo wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another " 805252726Srpaulo "interface", wps->uuid, UUID_LEN); 806252726Srpaulo } else { 807252726Srpaulo uuid_gen_mac_addr(hapd->own_addr, wps->uuid); 808252726Srpaulo wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC " 809252726Srpaulo "address", wps->uuid, UUID_LEN); 810252726Srpaulo } 811252726Srpaulo } else { 812252726Srpaulo os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN); 813252726Srpaulo wpa_hexdump(MSG_DEBUG, "WPS: Use configured UUID", 814214501Srpaulo wps->uuid, UUID_LEN); 815252726Srpaulo } 816214501Srpaulo wps->ssid_len = hapd->conf->ssid.ssid_len; 817214501Srpaulo os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len); 818214501Srpaulo wps->ap = 1; 819214501Srpaulo os_memcpy(wps->dev.mac_addr, hapd->own_addr, ETH_ALEN); 820214501Srpaulo wps->dev.device_name = hapd->conf->device_name ? 821214501Srpaulo os_strdup(hapd->conf->device_name) : NULL; 822214501Srpaulo wps->dev.manufacturer = hapd->conf->manufacturer ? 823214501Srpaulo os_strdup(hapd->conf->manufacturer) : NULL; 824214501Srpaulo wps->dev.model_name = hapd->conf->model_name ? 825214501Srpaulo os_strdup(hapd->conf->model_name) : NULL; 826214501Srpaulo wps->dev.model_number = hapd->conf->model_number ? 827214501Srpaulo os_strdup(hapd->conf->model_number) : NULL; 828214501Srpaulo wps->dev.serial_number = hapd->conf->serial_number ? 829214501Srpaulo os_strdup(hapd->conf->serial_number) : NULL; 830214501Srpaulo wps->config_methods = 831214501Srpaulo wps_config_methods_str2bin(hapd->conf->config_methods); 832252726Srpaulo#ifdef CONFIG_WPS2 833252726Srpaulo if ((wps->config_methods & 834252726Srpaulo (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY | 835252726Srpaulo WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) { 836252726Srpaulo wpa_printf(MSG_INFO, "WPS: Converting display to " 837252726Srpaulo "virtual_display for WPS 2.0 compliance"); 838252726Srpaulo wps->config_methods |= WPS_CONFIG_VIRT_DISPLAY; 839252726Srpaulo } 840252726Srpaulo if ((wps->config_methods & 841252726Srpaulo (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON | 842252726Srpaulo WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) { 843252726Srpaulo wpa_printf(MSG_INFO, "WPS: Converting push_button to " 844252726Srpaulo "virtual_push_button for WPS 2.0 compliance"); 845252726Srpaulo wps->config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON; 846252726Srpaulo } 847252726Srpaulo#endif /* CONFIG_WPS2 */ 848252726Srpaulo os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type, 849252726Srpaulo WPS_DEV_TYPE_LEN); 850252726Srpaulo 851252726Srpaulo if (hostapd_wps_set_vendor_ext(hapd, wps) < 0) { 852214501Srpaulo os_free(wps); 853214501Srpaulo return -1; 854214501Srpaulo } 855252726Srpaulo 856214501Srpaulo wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version); 857214501Srpaulo 858252726Srpaulo if (conf->wps_rf_bands) { 859252726Srpaulo wps->dev.rf_bands = conf->wps_rf_bands; 860252726Srpaulo } else { 861252726Srpaulo wps->dev.rf_bands = 862252726Srpaulo hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ? 863252726Srpaulo WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */ 864252726Srpaulo } 865252726Srpaulo 866214501Srpaulo if (conf->wpa & WPA_PROTO_RSN) { 867214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) 868214501Srpaulo wps->auth_types |= WPS_AUTH_WPA2PSK; 869214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) 870214501Srpaulo wps->auth_types |= WPS_AUTH_WPA2; 871214501Srpaulo 872214501Srpaulo if (conf->rsn_pairwise & WPA_CIPHER_CCMP) 873214501Srpaulo wps->encr_types |= WPS_ENCR_AES; 874214501Srpaulo if (conf->rsn_pairwise & WPA_CIPHER_TKIP) 875214501Srpaulo wps->encr_types |= WPS_ENCR_TKIP; 876214501Srpaulo } 877214501Srpaulo 878214501Srpaulo if (conf->wpa & WPA_PROTO_WPA) { 879214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) 880214501Srpaulo wps->auth_types |= WPS_AUTH_WPAPSK; 881214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) 882214501Srpaulo wps->auth_types |= WPS_AUTH_WPA; 883214501Srpaulo 884214501Srpaulo if (conf->wpa_pairwise & WPA_CIPHER_CCMP) 885214501Srpaulo wps->encr_types |= WPS_ENCR_AES; 886214501Srpaulo if (conf->wpa_pairwise & WPA_CIPHER_TKIP) 887214501Srpaulo wps->encr_types |= WPS_ENCR_TKIP; 888214501Srpaulo } 889214501Srpaulo 890214501Srpaulo if (conf->ssid.security_policy == SECURITY_PLAINTEXT) { 891214501Srpaulo wps->encr_types |= WPS_ENCR_NONE; 892214501Srpaulo wps->auth_types |= WPS_AUTH_OPEN; 893214501Srpaulo } else if (conf->ssid.security_policy == SECURITY_STATIC_WEP) { 894214501Srpaulo wps->encr_types |= WPS_ENCR_WEP; 895214501Srpaulo if (conf->auth_algs & WPA_AUTH_ALG_OPEN) 896214501Srpaulo wps->auth_types |= WPS_AUTH_OPEN; 897214501Srpaulo if (conf->auth_algs & WPA_AUTH_ALG_SHARED) 898214501Srpaulo wps->auth_types |= WPS_AUTH_SHARED; 899214501Srpaulo } else if (conf->ssid.security_policy == SECURITY_IEEE_802_1X) { 900214501Srpaulo wps->auth_types |= WPS_AUTH_OPEN; 901214501Srpaulo if (conf->default_wep_key_len) 902214501Srpaulo wps->encr_types |= WPS_ENCR_WEP; 903214501Srpaulo else 904214501Srpaulo wps->encr_types |= WPS_ENCR_NONE; 905214501Srpaulo } 906214501Srpaulo 907214501Srpaulo if (conf->ssid.wpa_psk_file) { 908214501Srpaulo /* Use per-device PSKs */ 909214501Srpaulo } else if (conf->ssid.wpa_passphrase) { 910214501Srpaulo wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase); 911214501Srpaulo wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase); 912214501Srpaulo } else if (conf->ssid.wpa_psk) { 913214501Srpaulo wps->network_key = os_malloc(2 * PMK_LEN + 1); 914214501Srpaulo if (wps->network_key == NULL) { 915214501Srpaulo os_free(wps); 916214501Srpaulo return -1; 917214501Srpaulo } 918214501Srpaulo wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1, 919214501Srpaulo conf->ssid.wpa_psk->psk, PMK_LEN); 920214501Srpaulo wps->network_key_len = 2 * PMK_LEN; 921214501Srpaulo } else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) { 922214501Srpaulo wps->network_key = os_malloc(conf->ssid.wep.len[0]); 923214501Srpaulo if (wps->network_key == NULL) { 924214501Srpaulo os_free(wps); 925214501Srpaulo return -1; 926214501Srpaulo } 927214501Srpaulo os_memcpy(wps->network_key, conf->ssid.wep.key[0], 928214501Srpaulo conf->ssid.wep.len[0]); 929214501Srpaulo wps->network_key_len = conf->ssid.wep.len[0]; 930214501Srpaulo } 931214501Srpaulo 932214501Srpaulo if (conf->ssid.wpa_psk) { 933214501Srpaulo os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN); 934214501Srpaulo wps->psk_set = 1; 935214501Srpaulo } 936214501Srpaulo 937214501Srpaulo if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) { 938214501Srpaulo /* Override parameters to enable security by default */ 939214501Srpaulo wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK; 940214501Srpaulo wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP; 941214501Srpaulo } 942214501Srpaulo 943214501Srpaulo wps->ap_settings = conf->ap_settings; 944214501Srpaulo wps->ap_settings_len = conf->ap_settings_len; 945214501Srpaulo 946214501Srpaulo cfg.new_psk_cb = hostapd_wps_new_psk_cb; 947214501Srpaulo cfg.set_ie_cb = hostapd_wps_set_ie_cb; 948214501Srpaulo cfg.pin_needed_cb = hostapd_wps_pin_needed_cb; 949214501Srpaulo cfg.reg_success_cb = hostapd_wps_reg_success_cb; 950214501Srpaulo cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb; 951214501Srpaulo cfg.cb_ctx = hapd; 952214501Srpaulo cfg.skip_cred_build = conf->skip_cred_build; 953214501Srpaulo cfg.extra_cred = conf->extra_cred; 954214501Srpaulo cfg.extra_cred_len = conf->extra_cred_len; 955214501Srpaulo cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) && 956214501Srpaulo conf->skip_cred_build; 957214501Srpaulo if (conf->ssid.security_policy == SECURITY_STATIC_WEP) 958214501Srpaulo cfg.static_wep_only = 1; 959252726Srpaulo cfg.dualband = interface_count(hapd->iface) > 1; 960252726Srpaulo if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) == 961252726Srpaulo (WPS_RF_50GHZ | WPS_RF_24GHZ)) 962252726Srpaulo cfg.dualband = 1; 963252726Srpaulo if (cfg.dualband) 964252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Dualband AP"); 965214501Srpaulo 966214501Srpaulo wps->registrar = wps_registrar_init(wps, &cfg); 967214501Srpaulo if (wps->registrar == NULL) { 968252726Srpaulo wpa_printf(MSG_ERROR, "Failed to initialize WPS Registrar"); 969214501Srpaulo os_free(wps->network_key); 970214501Srpaulo os_free(wps); 971214501Srpaulo return -1; 972214501Srpaulo } 973214501Srpaulo 974214501Srpaulo#ifdef CONFIG_WPS_UPNP 975214501Srpaulo wps->friendly_name = hapd->conf->friendly_name; 976214501Srpaulo wps->manufacturer_url = hapd->conf->manufacturer_url; 977214501Srpaulo wps->model_description = hapd->conf->model_description; 978214501Srpaulo wps->model_url = hapd->conf->model_url; 979214501Srpaulo wps->upc = hapd->conf->upc; 980252726Srpaulo#endif /* CONFIG_WPS_UPNP */ 981214501Srpaulo 982252726Srpaulo hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd); 983252726Srpaulo 984252726Srpaulo hapd->wps = wps; 985252726Srpaulo 986252726Srpaulo return 0; 987252726Srpaulo} 988252726Srpaulo 989252726Srpaulo 990252726Srpauloint hostapd_init_wps_complete(struct hostapd_data *hapd) 991252726Srpaulo{ 992252726Srpaulo struct wps_context *wps = hapd->wps; 993252726Srpaulo 994252726Srpaulo if (wps == NULL) 995252726Srpaulo return 0; 996252726Srpaulo 997252726Srpaulo#ifdef CONFIG_WPS_UPNP 998214501Srpaulo if (hostapd_wps_upnp_init(hapd, wps) < 0) { 999214501Srpaulo wpa_printf(MSG_ERROR, "Failed to initialize WPS UPnP"); 1000214501Srpaulo wps_registrar_deinit(wps->registrar); 1001214501Srpaulo os_free(wps->network_key); 1002214501Srpaulo os_free(wps); 1003252726Srpaulo hapd->wps = NULL; 1004214501Srpaulo return -1; 1005214501Srpaulo } 1006214501Srpaulo#endif /* CONFIG_WPS_UPNP */ 1007214501Srpaulo 1008252726Srpaulo return 0; 1009252726Srpaulo} 1010214501Srpaulo 1011214501Srpaulo 1012252726Srpaulostatic void hostapd_wps_nfc_clear(struct wps_context *wps) 1013252726Srpaulo{ 1014252726Srpaulo#ifdef CONFIG_WPS_NFC 1015252726Srpaulo wps->ap_nfc_dev_pw_id = 0; 1016252726Srpaulo wpabuf_free(wps->ap_nfc_dh_pubkey); 1017252726Srpaulo wps->ap_nfc_dh_pubkey = NULL; 1018252726Srpaulo wpabuf_free(wps->ap_nfc_dh_privkey); 1019252726Srpaulo wps->ap_nfc_dh_privkey = NULL; 1020252726Srpaulo wpabuf_free(wps->ap_nfc_dev_pw); 1021252726Srpaulo wps->ap_nfc_dev_pw = NULL; 1022252726Srpaulo#endif /* CONFIG_WPS_NFC */ 1023214501Srpaulo} 1024214501Srpaulo 1025214501Srpaulo 1026214501Srpaulovoid hostapd_deinit_wps(struct hostapd_data *hapd) 1027214501Srpaulo{ 1028214501Srpaulo eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); 1029214501Srpaulo eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); 1030214501Srpaulo if (hapd->wps == NULL) 1031214501Srpaulo return; 1032214501Srpaulo#ifdef CONFIG_WPS_UPNP 1033214501Srpaulo hostapd_wps_upnp_deinit(hapd); 1034214501Srpaulo#endif /* CONFIG_WPS_UPNP */ 1035214501Srpaulo wps_registrar_deinit(hapd->wps->registrar); 1036214501Srpaulo os_free(hapd->wps->network_key); 1037214501Srpaulo wps_device_data_free(&hapd->wps->dev); 1038214501Srpaulo wpabuf_free(hapd->wps->dh_pubkey); 1039214501Srpaulo wpabuf_free(hapd->wps->dh_privkey); 1040214501Srpaulo wps_free_pending_msgs(hapd->wps->upnp_msgs); 1041252726Srpaulo hostapd_wps_nfc_clear(hapd->wps); 1042214501Srpaulo os_free(hapd->wps); 1043214501Srpaulo hapd->wps = NULL; 1044214501Srpaulo hostapd_wps_clear_ies(hapd); 1045214501Srpaulo} 1046214501Srpaulo 1047214501Srpaulo 1048214501Srpaulovoid hostapd_update_wps(struct hostapd_data *hapd) 1049214501Srpaulo{ 1050214501Srpaulo if (hapd->wps == NULL) 1051214501Srpaulo return; 1052252726Srpaulo 1053252726Srpaulo#ifdef CONFIG_WPS_UPNP 1054252726Srpaulo hapd->wps->friendly_name = hapd->conf->friendly_name; 1055252726Srpaulo hapd->wps->manufacturer_url = hapd->conf->manufacturer_url; 1056252726Srpaulo hapd->wps->model_description = hapd->conf->model_description; 1057252726Srpaulo hapd->wps->model_url = hapd->conf->model_url; 1058252726Srpaulo hapd->wps->upc = hapd->conf->upc; 1059252726Srpaulo#endif /* CONFIG_WPS_UPNP */ 1060252726Srpaulo 1061252726Srpaulo hostapd_wps_set_vendor_ext(hapd, hapd->wps); 1062252726Srpaulo 1063214501Srpaulo if (hapd->conf->wps_state) 1064214501Srpaulo wps_registrar_update_ie(hapd->wps->registrar); 1065214501Srpaulo else 1066214501Srpaulo hostapd_deinit_wps(hapd); 1067214501Srpaulo} 1068214501Srpaulo 1069214501Srpaulo 1070252726Srpaulostruct wps_add_pin_data { 1071252726Srpaulo const u8 *addr; 1072252726Srpaulo const u8 *uuid; 1073252726Srpaulo const u8 *pin; 1074252726Srpaulo size_t pin_len; 1075252726Srpaulo int timeout; 1076252726Srpaulo int added; 1077252726Srpaulo}; 1078252726Srpaulo 1079252726Srpaulo 1080252726Srpaulostatic int wps_add_pin(struct hostapd_data *hapd, void *ctx) 1081214501Srpaulo{ 1082252726Srpaulo struct wps_add_pin_data *data = ctx; 1083252726Srpaulo int ret; 1084252726Srpaulo 1085252726Srpaulo if (hapd->wps == NULL) 1086252726Srpaulo return 0; 1087252726Srpaulo ret = wps_registrar_add_pin(hapd->wps->registrar, data->addr, 1088252726Srpaulo data->uuid, data->pin, data->pin_len, 1089252726Srpaulo data->timeout); 1090252726Srpaulo if (ret == 0) 1091252726Srpaulo data->added++; 1092252726Srpaulo return ret; 1093252726Srpaulo} 1094252726Srpaulo 1095252726Srpaulo 1096252726Srpauloint hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr, 1097252726Srpaulo const char *uuid, const char *pin, int timeout) 1098252726Srpaulo{ 1099214501Srpaulo u8 u[UUID_LEN]; 1100252726Srpaulo struct wps_add_pin_data data; 1101214501Srpaulo 1102252726Srpaulo data.addr = addr; 1103252726Srpaulo data.uuid = u; 1104252726Srpaulo data.pin = (const u8 *) pin; 1105252726Srpaulo data.pin_len = os_strlen(pin); 1106252726Srpaulo data.timeout = timeout; 1107252726Srpaulo data.added = 0; 1108252726Srpaulo 1109214501Srpaulo if (os_strcmp(uuid, "any") == 0) 1110252726Srpaulo data.uuid = NULL; 1111252726Srpaulo else { 1112252726Srpaulo if (uuid_str2bin(uuid, u)) 1113252726Srpaulo return -1; 1114252726Srpaulo data.uuid = u; 1115252726Srpaulo } 1116252726Srpaulo if (hostapd_wps_for_each(hapd, wps_add_pin, &data) < 0) 1117214501Srpaulo return -1; 1118252726Srpaulo return data.added ? 0 : -1; 1119214501Srpaulo} 1120214501Srpaulo 1121214501Srpaulo 1122252726Srpaulostatic int wps_button_pushed(struct hostapd_data *hapd, void *ctx) 1123214501Srpaulo{ 1124252726Srpaulo const u8 *p2p_dev_addr = ctx; 1125214501Srpaulo if (hapd->wps == NULL) 1126252726Srpaulo return 0; 1127252726Srpaulo return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr); 1128214501Srpaulo} 1129214501Srpaulo 1130214501Srpaulo 1131252726Srpauloint hostapd_wps_button_pushed(struct hostapd_data *hapd, 1132252726Srpaulo const u8 *p2p_dev_addr) 1133214501Srpaulo{ 1134252726Srpaulo return hostapd_wps_for_each(hapd, wps_button_pushed, 1135252726Srpaulo (void *) p2p_dev_addr); 1136252726Srpaulo} 1137214501Srpaulo 1138214501Srpaulo 1139252726Srpaulostatic int wps_cancel(struct hostapd_data *hapd, void *ctx) 1140252726Srpaulo{ 1141252726Srpaulo if (hapd->wps == NULL) 1142252726Srpaulo return 0; 1143214501Srpaulo 1144252726Srpaulo wps_registrar_wps_cancel(hapd->wps->registrar); 1145252726Srpaulo ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL); 1146214501Srpaulo 1147214501Srpaulo return 0; 1148252726Srpaulo} 1149214501Srpaulo 1150252726Srpaulo 1151252726Srpauloint hostapd_wps_cancel(struct hostapd_data *hapd) 1152252726Srpaulo{ 1153252726Srpaulo return hostapd_wps_for_each(hapd, wps_cancel, NULL); 1154214501Srpaulo} 1155214501Srpaulo 1156214501Srpaulo 1157252726Srpaulostatic int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da, 1158252726Srpaulo const u8 *bssid, 1159252726Srpaulo const u8 *ie, size_t ie_len, 1160252726Srpaulo int ssi_signal) 1161214501Srpaulo{ 1162214501Srpaulo struct hostapd_data *hapd = ctx; 1163214501Srpaulo struct wpabuf *wps_ie; 1164214501Srpaulo struct ieee802_11_elems elems; 1165214501Srpaulo 1166214501Srpaulo if (hapd->wps == NULL) 1167214501Srpaulo return 0; 1168214501Srpaulo 1169214501Srpaulo if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) { 1170214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Could not parse ProbeReq from " 1171214501Srpaulo MACSTR, MAC2STR(addr)); 1172214501Srpaulo return 0; 1173214501Srpaulo } 1174214501Srpaulo 1175214501Srpaulo if (elems.ssid && elems.ssid_len > 0 && 1176214501Srpaulo (elems.ssid_len != hapd->conf->ssid.ssid_len || 1177214501Srpaulo os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) != 1178214501Srpaulo 0)) 1179214501Srpaulo return 0; /* Not for us */ 1180214501Srpaulo 1181214501Srpaulo wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA); 1182214501Srpaulo if (wps_ie == NULL) 1183214501Srpaulo return 0; 1184252726Srpaulo if (wps_validate_probe_req(wps_ie, addr) < 0) { 1185252726Srpaulo wpabuf_free(wps_ie); 1186252726Srpaulo return 0; 1187252726Srpaulo } 1188214501Srpaulo 1189214501Srpaulo if (wpabuf_len(wps_ie) > 0) { 1190252726Srpaulo int p2p_wildcard = 0; 1191252726Srpaulo#ifdef CONFIG_P2P 1192252726Srpaulo if (elems.ssid && elems.ssid_len == P2P_WILDCARD_SSID_LEN && 1193252726Srpaulo os_memcmp(elems.ssid, P2P_WILDCARD_SSID, 1194252726Srpaulo P2P_WILDCARD_SSID_LEN) == 0) 1195252726Srpaulo p2p_wildcard = 1; 1196252726Srpaulo#endif /* CONFIG_P2P */ 1197252726Srpaulo wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie, 1198252726Srpaulo p2p_wildcard); 1199214501Srpaulo#ifdef CONFIG_WPS_UPNP 1200214501Srpaulo /* FIX: what exactly should be included in the WLANEvent? 1201214501Srpaulo * WPS attributes? Full ProbeReq frame? */ 1202252726Srpaulo if (!p2p_wildcard) 1203252726Srpaulo upnp_wps_device_send_wlan_event( 1204252726Srpaulo hapd->wps_upnp, addr, 1205252726Srpaulo UPNP_WPS_WLANEVENT_TYPE_PROBE, wps_ie); 1206214501Srpaulo#endif /* CONFIG_WPS_UPNP */ 1207214501Srpaulo } 1208214501Srpaulo 1209214501Srpaulo wpabuf_free(wps_ie); 1210214501Srpaulo 1211214501Srpaulo return 0; 1212214501Srpaulo} 1213214501Srpaulo 1214214501Srpaulo 1215214501Srpaulo#ifdef CONFIG_WPS_UPNP 1216214501Srpaulo 1217214501Srpaulostatic int hostapd_rx_req_put_wlan_response( 1218214501Srpaulo void *priv, enum upnp_wps_wlanevent_type ev_type, 1219214501Srpaulo const u8 *mac_addr, const struct wpabuf *msg, 1220214501Srpaulo enum wps_msg_type msg_type) 1221214501Srpaulo{ 1222214501Srpaulo struct hostapd_data *hapd = priv; 1223214501Srpaulo struct sta_info *sta; 1224214501Srpaulo struct upnp_pending_message *p; 1225214501Srpaulo 1226214501Srpaulo wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr=" 1227214501Srpaulo MACSTR, ev_type, MAC2STR(mac_addr)); 1228214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage", 1229214501Srpaulo wpabuf_head(msg), wpabuf_len(msg)); 1230214501Srpaulo if (ev_type != UPNP_WPS_WLANEVENT_TYPE_EAP) { 1231214501Srpaulo wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored unexpected " 1232214501Srpaulo "PutWLANResponse WLANEventType %d", ev_type); 1233214501Srpaulo return -1; 1234214501Srpaulo } 1235214501Srpaulo 1236214501Srpaulo /* 1237214501Srpaulo * EAP response to ongoing to WPS Registration. Send it to EAP-WSC 1238214501Srpaulo * server implementation for delivery to the peer. 1239214501Srpaulo */ 1240214501Srpaulo 1241214501Srpaulo sta = ap_get_sta(hapd, mac_addr); 1242252726Srpaulo#ifndef CONFIG_WPS_STRICT 1243214501Srpaulo if (!sta) { 1244214501Srpaulo /* 1245214501Srpaulo * Workaround - Intel wsccmd uses bogus NewWLANEventMAC: 1246214501Srpaulo * Pick STA that is in an ongoing WPS registration without 1247214501Srpaulo * checking the MAC address. 1248214501Srpaulo */ 1249214501Srpaulo wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found based " 1250214501Srpaulo "on NewWLANEventMAC; try wildcard match"); 1251214501Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 1252214501Srpaulo if (sta->eapol_sm && (sta->flags & WLAN_STA_WPS)) 1253214501Srpaulo break; 1254214501Srpaulo } 1255214501Srpaulo } 1256252726Srpaulo#endif /* CONFIG_WPS_STRICT */ 1257214501Srpaulo 1258252726Srpaulo if (!sta || !(sta->flags & WLAN_STA_WPS)) { 1259214501Srpaulo wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found"); 1260214501Srpaulo return 0; 1261214501Srpaulo } 1262214501Srpaulo 1263214501Srpaulo p = os_zalloc(sizeof(*p)); 1264214501Srpaulo if (p == NULL) 1265214501Srpaulo return -1; 1266214501Srpaulo os_memcpy(p->addr, sta->addr, ETH_ALEN); 1267214501Srpaulo p->msg = wpabuf_dup(msg); 1268214501Srpaulo p->type = msg_type; 1269214501Srpaulo p->next = hapd->wps->upnp_msgs; 1270214501Srpaulo hapd->wps->upnp_msgs = p; 1271214501Srpaulo 1272214501Srpaulo return eapol_auth_eap_pending_cb(sta->eapol_sm, sta->eapol_sm->eap); 1273214501Srpaulo} 1274214501Srpaulo 1275214501Srpaulo 1276214501Srpaulostatic int hostapd_wps_upnp_init(struct hostapd_data *hapd, 1277214501Srpaulo struct wps_context *wps) 1278214501Srpaulo{ 1279214501Srpaulo struct upnp_wps_device_ctx *ctx; 1280214501Srpaulo 1281214501Srpaulo if (!hapd->conf->upnp_iface) 1282214501Srpaulo return 0; 1283214501Srpaulo ctx = os_zalloc(sizeof(*ctx)); 1284214501Srpaulo if (ctx == NULL) 1285214501Srpaulo return -1; 1286214501Srpaulo 1287214501Srpaulo ctx->rx_req_put_wlan_response = hostapd_rx_req_put_wlan_response; 1288214501Srpaulo if (hapd->conf->ap_pin) 1289214501Srpaulo ctx->ap_pin = os_strdup(hapd->conf->ap_pin); 1290214501Srpaulo 1291252726Srpaulo hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd, 1292252726Srpaulo hapd->conf->upnp_iface); 1293252726Srpaulo if (hapd->wps_upnp == NULL) 1294214501Srpaulo return -1; 1295214501Srpaulo wps->wps_upnp = hapd->wps_upnp; 1296214501Srpaulo 1297214501Srpaulo return 0; 1298214501Srpaulo} 1299214501Srpaulo 1300214501Srpaulo 1301214501Srpaulostatic void hostapd_wps_upnp_deinit(struct hostapd_data *hapd) 1302214501Srpaulo{ 1303252726Srpaulo upnp_wps_device_deinit(hapd->wps_upnp, hapd); 1304214501Srpaulo} 1305214501Srpaulo 1306214501Srpaulo#endif /* CONFIG_WPS_UPNP */ 1307214501Srpaulo 1308214501Srpaulo 1309214501Srpauloint hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr, 1310214501Srpaulo char *buf, size_t buflen) 1311214501Srpaulo{ 1312214501Srpaulo if (hapd->wps == NULL) 1313214501Srpaulo return 0; 1314214501Srpaulo return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen); 1315214501Srpaulo} 1316214501Srpaulo 1317214501Srpaulo 1318214501Srpaulostatic void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx) 1319214501Srpaulo{ 1320214501Srpaulo struct hostapd_data *hapd = eloop_data; 1321214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out"); 1322214501Srpaulo hostapd_wps_ap_pin_disable(hapd); 1323252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_PIN_DISABLED); 1324214501Srpaulo} 1325214501Srpaulo 1326214501Srpaulo 1327214501Srpaulostatic void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout) 1328214501Srpaulo{ 1329214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout); 1330214501Srpaulo hapd->ap_pin_failures = 0; 1331252726Srpaulo hapd->ap_pin_failures_consecutive = 0; 1332214501Srpaulo hapd->conf->ap_setup_locked = 0; 1333214501Srpaulo if (hapd->wps->ap_setup_locked) { 1334214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED); 1335214501Srpaulo hapd->wps->ap_setup_locked = 0; 1336214501Srpaulo wps_registrar_update_ie(hapd->wps->registrar); 1337214501Srpaulo } 1338214501Srpaulo eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); 1339214501Srpaulo if (timeout > 0) 1340214501Srpaulo eloop_register_timeout(timeout, 0, 1341214501Srpaulo hostapd_wps_ap_pin_timeout, hapd, NULL); 1342214501Srpaulo} 1343214501Srpaulo 1344214501Srpaulo 1345252726Srpaulostatic int wps_ap_pin_disable(struct hostapd_data *hapd, void *ctx) 1346214501Srpaulo{ 1347214501Srpaulo os_free(hapd->conf->ap_pin); 1348214501Srpaulo hapd->conf->ap_pin = NULL; 1349214501Srpaulo#ifdef CONFIG_WPS_UPNP 1350214501Srpaulo upnp_wps_set_ap_pin(hapd->wps_upnp, NULL); 1351214501Srpaulo#endif /* CONFIG_WPS_UPNP */ 1352214501Srpaulo eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); 1353252726Srpaulo return 0; 1354214501Srpaulo} 1355214501Srpaulo 1356214501Srpaulo 1357252726Srpaulovoid hostapd_wps_ap_pin_disable(struct hostapd_data *hapd) 1358214501Srpaulo{ 1359252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN"); 1360252726Srpaulo hostapd_wps_for_each(hapd, wps_ap_pin_disable, NULL); 1361252726Srpaulo} 1362252726Srpaulo 1363252726Srpaulo 1364252726Srpaulostruct wps_ap_pin_data { 1365214501Srpaulo char pin_txt[9]; 1366252726Srpaulo int timeout; 1367252726Srpaulo}; 1368214501Srpaulo 1369252726Srpaulo 1370252726Srpaulostatic int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx) 1371252726Srpaulo{ 1372252726Srpaulo struct wps_ap_pin_data *data = ctx; 1373214501Srpaulo os_free(hapd->conf->ap_pin); 1374252726Srpaulo hapd->conf->ap_pin = os_strdup(data->pin_txt); 1375214501Srpaulo#ifdef CONFIG_WPS_UPNP 1376252726Srpaulo upnp_wps_set_ap_pin(hapd->wps_upnp, data->pin_txt); 1377214501Srpaulo#endif /* CONFIG_WPS_UPNP */ 1378252726Srpaulo hostapd_wps_ap_pin_enable(hapd, data->timeout); 1379252726Srpaulo return 0; 1380252726Srpaulo} 1381252726Srpaulo 1382252726Srpaulo 1383252726Srpauloconst char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout) 1384252726Srpaulo{ 1385252726Srpaulo unsigned int pin; 1386252726Srpaulo struct wps_ap_pin_data data; 1387252726Srpaulo 1388252726Srpaulo pin = wps_generate_pin(); 1389252726Srpaulo os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin); 1390252726Srpaulo data.timeout = timeout; 1391252726Srpaulo hostapd_wps_for_each(hapd, wps_ap_pin_set, &data); 1392214501Srpaulo return hapd->conf->ap_pin; 1393214501Srpaulo} 1394214501Srpaulo 1395214501Srpaulo 1396214501Srpauloconst char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd) 1397214501Srpaulo{ 1398214501Srpaulo return hapd->conf->ap_pin; 1399214501Srpaulo} 1400214501Srpaulo 1401214501Srpaulo 1402214501Srpauloint hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin, 1403214501Srpaulo int timeout) 1404214501Srpaulo{ 1405252726Srpaulo struct wps_ap_pin_data data; 1406252726Srpaulo int ret; 1407252726Srpaulo 1408252726Srpaulo ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin); 1409252726Srpaulo if (ret < 0 || ret >= (int) sizeof(data.pin_txt)) 1410214501Srpaulo return -1; 1411252726Srpaulo data.timeout = timeout; 1412252726Srpaulo return hostapd_wps_for_each(hapd, wps_ap_pin_set, &data); 1413252726Srpaulo} 1414252726Srpaulo 1415252726Srpaulo 1416252726Srpaulostatic int wps_update_ie(struct hostapd_data *hapd, void *ctx) 1417252726Srpaulo{ 1418252726Srpaulo if (hapd->wps) 1419252726Srpaulo wps_registrar_update_ie(hapd->wps->registrar); 1420214501Srpaulo return 0; 1421214501Srpaulo} 1422252726Srpaulo 1423252726Srpaulo 1424252726Srpaulovoid hostapd_wps_update_ie(struct hostapd_data *hapd) 1425252726Srpaulo{ 1426252726Srpaulo hostapd_wps_for_each(hapd, wps_update_ie, NULL); 1427252726Srpaulo} 1428252726Srpaulo 1429252726Srpaulo 1430252726Srpauloint hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid, 1431252726Srpaulo const char *auth, const char *encr, const char *key) 1432252726Srpaulo{ 1433252726Srpaulo struct wps_credential cred; 1434252726Srpaulo size_t len; 1435252726Srpaulo 1436252726Srpaulo os_memset(&cred, 0, sizeof(cred)); 1437252726Srpaulo 1438252726Srpaulo len = os_strlen(ssid); 1439252726Srpaulo if ((len & 1) || len > 2 * sizeof(cred.ssid) || 1440252726Srpaulo hexstr2bin(ssid, cred.ssid, len / 2)) 1441252726Srpaulo return -1; 1442252726Srpaulo cred.ssid_len = len / 2; 1443252726Srpaulo 1444252726Srpaulo if (os_strncmp(auth, "OPEN", 4) == 0) 1445252726Srpaulo cred.auth_type = WPS_AUTH_OPEN; 1446252726Srpaulo else if (os_strncmp(auth, "WPAPSK", 6) == 0) 1447252726Srpaulo cred.auth_type = WPS_AUTH_WPAPSK; 1448252726Srpaulo else if (os_strncmp(auth, "WPA2PSK", 7) == 0) 1449252726Srpaulo cred.auth_type = WPS_AUTH_WPA2PSK; 1450252726Srpaulo else 1451252726Srpaulo return -1; 1452252726Srpaulo 1453252726Srpaulo if (encr) { 1454252726Srpaulo if (os_strncmp(encr, "NONE", 4) == 0) 1455252726Srpaulo cred.encr_type = WPS_ENCR_NONE; 1456252726Srpaulo else if (os_strncmp(encr, "WEP", 3) == 0) 1457252726Srpaulo cred.encr_type = WPS_ENCR_WEP; 1458252726Srpaulo else if (os_strncmp(encr, "TKIP", 4) == 0) 1459252726Srpaulo cred.encr_type = WPS_ENCR_TKIP; 1460252726Srpaulo else if (os_strncmp(encr, "CCMP", 4) == 0) 1461252726Srpaulo cred.encr_type = WPS_ENCR_AES; 1462252726Srpaulo else 1463252726Srpaulo return -1; 1464252726Srpaulo } else 1465252726Srpaulo cred.encr_type = WPS_ENCR_NONE; 1466252726Srpaulo 1467252726Srpaulo if (key) { 1468252726Srpaulo len = os_strlen(key); 1469252726Srpaulo if ((len & 1) || len > 2 * sizeof(cred.key) || 1470252726Srpaulo hexstr2bin(key, cred.key, len / 2)) 1471252726Srpaulo return -1; 1472252726Srpaulo cred.key_len = len / 2; 1473252726Srpaulo } 1474252726Srpaulo 1475252726Srpaulo return wps_registrar_config_ap(hapd->wps->registrar, &cred); 1476252726Srpaulo} 1477252726Srpaulo 1478252726Srpaulo 1479252726Srpaulo#ifdef CONFIG_WPS_NFC 1480252726Srpaulo 1481252726Srpaulostruct wps_nfc_password_token_data { 1482252726Srpaulo const u8 *oob_dev_pw; 1483252726Srpaulo size_t oob_dev_pw_len; 1484252726Srpaulo int added; 1485252726Srpaulo}; 1486252726Srpaulo 1487252726Srpaulo 1488252726Srpaulostatic int wps_add_nfc_password_token(struct hostapd_data *hapd, void *ctx) 1489252726Srpaulo{ 1490252726Srpaulo struct wps_nfc_password_token_data *data = ctx; 1491252726Srpaulo int ret; 1492252726Srpaulo 1493252726Srpaulo if (hapd->wps == NULL) 1494252726Srpaulo return 0; 1495252726Srpaulo ret = wps_registrar_add_nfc_password_token(hapd->wps->registrar, 1496252726Srpaulo data->oob_dev_pw, 1497252726Srpaulo data->oob_dev_pw_len); 1498252726Srpaulo if (ret == 0) 1499252726Srpaulo data->added++; 1500252726Srpaulo return ret; 1501252726Srpaulo} 1502252726Srpaulo 1503252726Srpaulo 1504252726Srpaulostatic int hostapd_wps_add_nfc_password_token(struct hostapd_data *hapd, 1505252726Srpaulo struct wps_parse_attr *attr) 1506252726Srpaulo{ 1507252726Srpaulo struct wps_nfc_password_token_data data; 1508252726Srpaulo 1509252726Srpaulo data.oob_dev_pw = attr->oob_dev_password; 1510252726Srpaulo data.oob_dev_pw_len = attr->oob_dev_password_len; 1511252726Srpaulo data.added = 0; 1512252726Srpaulo if (hostapd_wps_for_each(hapd, wps_add_nfc_password_token, &data) < 0) 1513252726Srpaulo return -1; 1514252726Srpaulo return data.added ? 0 : -1; 1515252726Srpaulo} 1516252726Srpaulo 1517252726Srpaulo 1518252726Srpaulostatic int hostapd_wps_nfc_tag_process(struct hostapd_data *hapd, 1519252726Srpaulo const struct wpabuf *wps) 1520252726Srpaulo{ 1521252726Srpaulo struct wps_parse_attr attr; 1522252726Srpaulo 1523252726Srpaulo wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps); 1524252726Srpaulo 1525252726Srpaulo if (wps_parse_msg(wps, &attr)) { 1526252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag"); 1527252726Srpaulo return -1; 1528252726Srpaulo } 1529252726Srpaulo 1530252726Srpaulo if (attr.oob_dev_password) 1531252726Srpaulo return hostapd_wps_add_nfc_password_token(hapd, &attr); 1532252726Srpaulo 1533252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag"); 1534252726Srpaulo return -1; 1535252726Srpaulo} 1536252726Srpaulo 1537252726Srpaulo 1538252726Srpauloint hostapd_wps_nfc_tag_read(struct hostapd_data *hapd, 1539252726Srpaulo const struct wpabuf *data) 1540252726Srpaulo{ 1541252726Srpaulo const struct wpabuf *wps = data; 1542252726Srpaulo struct wpabuf *tmp = NULL; 1543252726Srpaulo int ret; 1544252726Srpaulo 1545252726Srpaulo if (wpabuf_len(data) < 4) 1546252726Srpaulo return -1; 1547252726Srpaulo 1548252726Srpaulo if (*wpabuf_head_u8(data) != 0x10) { 1549252726Srpaulo /* Assume this contains full NDEF record */ 1550252726Srpaulo tmp = ndef_parse_wifi(data); 1551252726Srpaulo if (tmp == NULL) { 1552252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF"); 1553252726Srpaulo return -1; 1554252726Srpaulo } 1555252726Srpaulo wps = tmp; 1556252726Srpaulo } 1557252726Srpaulo 1558252726Srpaulo ret = hostapd_wps_nfc_tag_process(hapd, wps); 1559252726Srpaulo wpabuf_free(tmp); 1560252726Srpaulo return ret; 1561252726Srpaulo} 1562252726Srpaulo 1563252726Srpaulo 1564252726Srpaulostruct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd, 1565252726Srpaulo int ndef) 1566252726Srpaulo{ 1567252726Srpaulo struct wpabuf *ret; 1568252726Srpaulo 1569252726Srpaulo if (hapd->wps == NULL) 1570252726Srpaulo return NULL; 1571252726Srpaulo 1572252726Srpaulo ret = wps_get_oob_cred(hapd->wps); 1573252726Srpaulo if (ndef && ret) { 1574252726Srpaulo struct wpabuf *tmp; 1575252726Srpaulo tmp = ndef_build_wifi(ret); 1576252726Srpaulo wpabuf_free(ret); 1577252726Srpaulo if (tmp == NULL) 1578252726Srpaulo return NULL; 1579252726Srpaulo ret = tmp; 1580252726Srpaulo } 1581252726Srpaulo 1582252726Srpaulo return ret; 1583252726Srpaulo} 1584252726Srpaulo 1585252726Srpaulo 1586252726Srpaulostruct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef) 1587252726Srpaulo{ 1588252726Srpaulo return wps_nfc_token_gen(ndef, &hapd->conf->wps_nfc_dev_pw_id, 1589252726Srpaulo &hapd->conf->wps_nfc_dh_pubkey, 1590252726Srpaulo &hapd->conf->wps_nfc_dh_privkey, 1591252726Srpaulo &hapd->conf->wps_nfc_dev_pw); 1592252726Srpaulo} 1593252726Srpaulo 1594252726Srpaulo 1595252726Srpauloint hostapd_wps_nfc_token_enable(struct hostapd_data *hapd) 1596252726Srpaulo{ 1597252726Srpaulo struct wps_context *wps = hapd->wps; 1598252726Srpaulo 1599252726Srpaulo if (wps == NULL) 1600252726Srpaulo return -1; 1601252726Srpaulo 1602252726Srpaulo if (!hapd->conf->wps_nfc_dh_pubkey || 1603252726Srpaulo !hapd->conf->wps_nfc_dh_privkey || 1604252726Srpaulo !hapd->conf->wps_nfc_dev_pw || 1605252726Srpaulo !hapd->conf->wps_nfc_dev_pw_id) 1606252726Srpaulo return -1; 1607252726Srpaulo 1608252726Srpaulo hostapd_wps_nfc_clear(wps); 1609252726Srpaulo wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id; 1610252726Srpaulo wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey); 1611252726Srpaulo wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey); 1612252726Srpaulo wps->ap_nfc_dev_pw = wpabuf_dup(hapd->conf->wps_nfc_dev_pw); 1613252726Srpaulo 1614252726Srpaulo if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey || 1615252726Srpaulo !wps->ap_nfc_dev_pw) { 1616252726Srpaulo hostapd_wps_nfc_clear(wps); 1617252726Srpaulo return -1; 1618252726Srpaulo } 1619252726Srpaulo 1620252726Srpaulo return 0; 1621252726Srpaulo} 1622252726Srpaulo 1623252726Srpaulo 1624252726Srpaulovoid hostapd_wps_nfc_token_disable(struct hostapd_data *hapd) 1625252726Srpaulo{ 1626252726Srpaulo hostapd_wps_nfc_clear(hapd->wps); 1627252726Srpaulo} 1628252726Srpaulo 1629252726Srpaulo#endif /* CONFIG_WPS_NFC */ 1630