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); 43281806Srpaulostatic void hostapd_wps_nfc_clear(struct wps_context *wps); 44214501Srpaulo 45214501Srpaulo 46252726Srpaulostruct wps_for_each_data { 47252726Srpaulo int (*func)(struct hostapd_data *h, void *ctx); 48252726Srpaulo void *ctx; 49281806Srpaulo struct hostapd_data *calling_hapd; 50252726Srpaulo}; 51252726Srpaulo 52252726Srpaulo 53252726Srpaulostatic int wps_for_each(struct hostapd_iface *iface, void *ctx) 54252726Srpaulo{ 55252726Srpaulo struct wps_for_each_data *data = ctx; 56252726Srpaulo size_t j; 57252726Srpaulo 58252726Srpaulo if (iface == NULL) 59252726Srpaulo return 0; 60252726Srpaulo for (j = 0; j < iface->num_bss; j++) { 61252726Srpaulo struct hostapd_data *hapd = iface->bss[j]; 62281806Srpaulo int ret; 63281806Srpaulo 64281806Srpaulo if (hapd != data->calling_hapd && 65281806Srpaulo (hapd->conf->wps_independent || 66281806Srpaulo data->calling_hapd->conf->wps_independent)) 67281806Srpaulo continue; 68281806Srpaulo 69281806Srpaulo ret = data->func(hapd, data->ctx); 70252726Srpaulo if (ret) 71252726Srpaulo return ret; 72252726Srpaulo } 73252726Srpaulo 74252726Srpaulo return 0; 75252726Srpaulo} 76252726Srpaulo 77252726Srpaulo 78252726Srpaulostatic int hostapd_wps_for_each(struct hostapd_data *hapd, 79252726Srpaulo int (*func)(struct hostapd_data *h, void *ctx), 80252726Srpaulo void *ctx) 81252726Srpaulo{ 82252726Srpaulo struct hostapd_iface *iface = hapd->iface; 83252726Srpaulo struct wps_for_each_data data; 84252726Srpaulo data.func = func; 85252726Srpaulo data.ctx = ctx; 86281806Srpaulo data.calling_hapd = hapd; 87252726Srpaulo if (iface->interfaces == NULL || 88252726Srpaulo iface->interfaces->for_each_interface == NULL) 89252726Srpaulo return wps_for_each(iface, &data); 90252726Srpaulo return iface->interfaces->for_each_interface(iface->interfaces, 91252726Srpaulo wps_for_each, &data); 92252726Srpaulo} 93252726Srpaulo 94252726Srpaulo 95281806Srpaulostatic int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, 96281806Srpaulo const u8 *p2p_dev_addr, const u8 *psk, 97214501Srpaulo size_t psk_len) 98214501Srpaulo{ 99214501Srpaulo struct hostapd_data *hapd = ctx; 100214501Srpaulo struct hostapd_wpa_psk *p; 101214501Srpaulo struct hostapd_ssid *ssid = &hapd->conf->ssid; 102214501Srpaulo 103281806Srpaulo if (is_zero_ether_addr(p2p_dev_addr)) { 104281806Srpaulo wpa_printf(MSG_DEBUG, 105281806Srpaulo "Received new WPA/WPA2-PSK from WPS for STA " MACSTR, 106281806Srpaulo MAC2STR(mac_addr)); 107281806Srpaulo } else { 108281806Srpaulo wpa_printf(MSG_DEBUG, 109281806Srpaulo "Received new WPA/WPA2-PSK from WPS for STA " MACSTR 110281806Srpaulo " P2P Device Addr " MACSTR, 111281806Srpaulo MAC2STR(mac_addr), MAC2STR(p2p_dev_addr)); 112281806Srpaulo } 113214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len); 114214501Srpaulo 115214501Srpaulo if (psk_len != PMK_LEN) { 116214501Srpaulo wpa_printf(MSG_DEBUG, "Unexpected PSK length %lu", 117214501Srpaulo (unsigned long) psk_len); 118214501Srpaulo return -1; 119214501Srpaulo } 120214501Srpaulo 121214501Srpaulo /* Add the new PSK to runtime PSK list */ 122214501Srpaulo p = os_zalloc(sizeof(*p)); 123214501Srpaulo if (p == NULL) 124214501Srpaulo return -1; 125214501Srpaulo os_memcpy(p->addr, mac_addr, ETH_ALEN); 126281806Srpaulo os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN); 127214501Srpaulo os_memcpy(p->psk, psk, PMK_LEN); 128214501Srpaulo 129281806Srpaulo if (hapd->new_psk_cb) { 130281806Srpaulo hapd->new_psk_cb(hapd->new_psk_cb_ctx, mac_addr, p2p_dev_addr, 131281806Srpaulo psk, psk_len); 132281806Srpaulo } 133281806Srpaulo 134214501Srpaulo p->next = ssid->wpa_psk; 135214501Srpaulo ssid->wpa_psk = p; 136214501Srpaulo 137214501Srpaulo if (ssid->wpa_psk_file) { 138214501Srpaulo FILE *f; 139214501Srpaulo char hex[PMK_LEN * 2 + 1]; 140214501Srpaulo /* Add the new PSK to PSK list file */ 141214501Srpaulo f = fopen(ssid->wpa_psk_file, "a"); 142214501Srpaulo if (f == NULL) { 143214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to add the PSK to " 144214501Srpaulo "'%s'", ssid->wpa_psk_file); 145214501Srpaulo return -1; 146214501Srpaulo } 147214501Srpaulo 148214501Srpaulo wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len); 149214501Srpaulo fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex); 150214501Srpaulo fclose(f); 151214501Srpaulo } 152214501Srpaulo 153214501Srpaulo return 0; 154214501Srpaulo} 155214501Srpaulo 156214501Srpaulo 157214501Srpaulostatic int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie, 158214501Srpaulo struct wpabuf *probe_resp_ie) 159214501Srpaulo{ 160214501Srpaulo struct hostapd_data *hapd = ctx; 161214501Srpaulo wpabuf_free(hapd->wps_beacon_ie); 162214501Srpaulo hapd->wps_beacon_ie = beacon_ie; 163214501Srpaulo wpabuf_free(hapd->wps_probe_resp_ie); 164214501Srpaulo hapd->wps_probe_resp_ie = probe_resp_ie; 165252726Srpaulo if (hapd->beacon_set_done) 166252726Srpaulo ieee802_11_set_beacon(hapd); 167252726Srpaulo return hostapd_set_ap_wps_ie(hapd); 168214501Srpaulo} 169214501Srpaulo 170214501Srpaulo 171214501Srpaulostatic void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e, 172214501Srpaulo const struct wps_device_data *dev) 173214501Srpaulo{ 174214501Srpaulo struct hostapd_data *hapd = ctx; 175214501Srpaulo char uuid[40], txt[400]; 176214501Srpaulo int len; 177214501Srpaulo char devtype[WPS_DEV_TYPE_BUFSIZE]; 178214501Srpaulo if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) 179214501Srpaulo return; 180214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: PIN needed for E-UUID %s", uuid); 181214501Srpaulo len = os_snprintf(txt, sizeof(txt), WPS_EVENT_PIN_NEEDED 182214501Srpaulo "%s " MACSTR " [%s|%s|%s|%s|%s|%s]", 183214501Srpaulo uuid, MAC2STR(dev->mac_addr), dev->device_name, 184214501Srpaulo dev->manufacturer, dev->model_name, 185214501Srpaulo dev->model_number, dev->serial_number, 186214501Srpaulo wps_dev_type_bin2str(dev->pri_dev_type, devtype, 187214501Srpaulo sizeof(devtype))); 188281806Srpaulo if (!os_snprintf_error(sizeof(txt), len)) 189214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt); 190214501Srpaulo 191214501Srpaulo if (hapd->conf->wps_pin_requests) { 192214501Srpaulo FILE *f; 193214501Srpaulo struct os_time t; 194214501Srpaulo f = fopen(hapd->conf->wps_pin_requests, "a"); 195214501Srpaulo if (f == NULL) 196214501Srpaulo return; 197214501Srpaulo os_get_time(&t); 198214501Srpaulo fprintf(f, "%ld\t%s\t" MACSTR "\t%s\t%s\t%s\t%s\t%s" 199214501Srpaulo "\t%s\n", 200214501Srpaulo t.sec, uuid, MAC2STR(dev->mac_addr), dev->device_name, 201214501Srpaulo dev->manufacturer, dev->model_name, dev->model_number, 202214501Srpaulo dev->serial_number, 203214501Srpaulo wps_dev_type_bin2str(dev->pri_dev_type, devtype, 204214501Srpaulo sizeof(devtype))); 205214501Srpaulo fclose(f); 206214501Srpaulo } 207214501Srpaulo} 208214501Srpaulo 209214501Srpaulo 210252726Srpaulostruct wps_stop_reg_data { 211252726Srpaulo struct hostapd_data *current_hapd; 212252726Srpaulo const u8 *uuid_e; 213252726Srpaulo const u8 *dev_pw; 214252726Srpaulo size_t dev_pw_len; 215252726Srpaulo}; 216252726Srpaulo 217252726Srpaulostatic int wps_stop_registrar(struct hostapd_data *hapd, void *ctx) 218252726Srpaulo{ 219252726Srpaulo struct wps_stop_reg_data *data = ctx; 220252726Srpaulo if (hapd != data->current_hapd && hapd->wps != NULL) 221252726Srpaulo wps_registrar_complete(hapd->wps->registrar, data->uuid_e, 222252726Srpaulo data->dev_pw, data->dev_pw_len); 223252726Srpaulo return 0; 224252726Srpaulo} 225252726Srpaulo 226252726Srpaulo 227214501Srpaulostatic void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr, 228252726Srpaulo const u8 *uuid_e, const u8 *dev_pw, 229252726Srpaulo size_t dev_pw_len) 230214501Srpaulo{ 231214501Srpaulo struct hostapd_data *hapd = ctx; 232214501Srpaulo char uuid[40]; 233252726Srpaulo struct wps_stop_reg_data data; 234214501Srpaulo if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) 235214501Srpaulo return; 236214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s", 237214501Srpaulo MAC2STR(mac_addr), uuid); 238214501Srpaulo if (hapd->wps_reg_success_cb) 239214501Srpaulo hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx, 240214501Srpaulo mac_addr, uuid_e); 241252726Srpaulo data.current_hapd = hapd; 242252726Srpaulo data.uuid_e = uuid_e; 243252726Srpaulo data.dev_pw = dev_pw; 244252726Srpaulo data.dev_pw_len = dev_pw_len; 245252726Srpaulo hostapd_wps_for_each(hapd, wps_stop_registrar, &data); 246214501Srpaulo} 247214501Srpaulo 248214501Srpaulo 249214501Srpaulostatic void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr, 250214501Srpaulo const u8 *uuid_e, 251214501Srpaulo const u8 *pri_dev_type, 252214501Srpaulo u16 config_methods, 253214501Srpaulo u16 dev_password_id, u8 request_type, 254214501Srpaulo const char *dev_name) 255214501Srpaulo{ 256214501Srpaulo struct hostapd_data *hapd = ctx; 257214501Srpaulo char uuid[40]; 258214501Srpaulo char devtype[WPS_DEV_TYPE_BUFSIZE]; 259214501Srpaulo if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) 260214501Srpaulo return; 261214501Srpaulo if (dev_name == NULL) 262214501Srpaulo dev_name = ""; 263214501Srpaulo wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ENROLLEE_SEEN MACSTR 264214501Srpaulo " %s %s 0x%x %u %u [%s]", 265214501Srpaulo MAC2STR(addr), uuid, 266214501Srpaulo wps_dev_type_bin2str(pri_dev_type, devtype, 267214501Srpaulo sizeof(devtype)), 268214501Srpaulo config_methods, dev_password_id, request_type, dev_name); 269214501Srpaulo} 270214501Srpaulo 271214501Srpaulo 272214501Srpaulostatic int str_starts(const char *str, const char *start) 273214501Srpaulo{ 274214501Srpaulo return os_strncmp(str, start, os_strlen(start)) == 0; 275214501Srpaulo} 276214501Srpaulo 277214501Srpaulo 278214501Srpaulostatic void wps_reload_config(void *eloop_data, void *user_ctx) 279214501Srpaulo{ 280214501Srpaulo struct hostapd_iface *iface = eloop_data; 281214501Srpaulo 282214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Reload configuration data"); 283252726Srpaulo if (iface->interfaces == NULL || 284252726Srpaulo iface->interfaces->reload_config(iface) < 0) { 285214501Srpaulo wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated " 286214501Srpaulo "configuration"); 287214501Srpaulo } 288214501Srpaulo} 289214501Srpaulo 290214501Srpaulo 291281806Srpaulovoid hostapd_wps_eap_completed(struct hostapd_data *hapd) 292281806Srpaulo{ 293281806Srpaulo /* 294281806Srpaulo * Reduce race condition of the station trying to reconnect immediately 295281806Srpaulo * after AP reconfiguration through WPS by rescheduling the reload 296281806Srpaulo * timeout to happen after EAP completion rather than the originally 297281806Srpaulo * scheduled 100 ms after new configuration became known. 298281806Srpaulo */ 299281806Srpaulo if (eloop_deplete_timeout(0, 0, wps_reload_config, hapd->iface, NULL) == 300281806Srpaulo 1) 301281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: Reschedule immediate configuration reload"); 302281806Srpaulo} 303281806Srpaulo 304281806Srpaulo 305252726Srpaulostatic void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr, 306252726Srpaulo size_t attr_len) 307214501Srpaulo{ 308252726Srpaulo size_t blen = attr_len * 2 + 1; 309252726Srpaulo char *buf = os_malloc(blen); 310252726Srpaulo if (buf) { 311252726Srpaulo wpa_snprintf_hex(buf, blen, attr, attr_len); 312252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, 313252726Srpaulo WPS_EVENT_NEW_AP_SETTINGS "%s", buf); 314252726Srpaulo os_free(buf); 315252726Srpaulo } 316252726Srpaulo} 317252726Srpaulo 318252726Srpaulo 319281806Srpaulostatic int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd, 320281806Srpaulo const struct wps_credential *cred) 321281806Srpaulo{ 322281806Srpaulo struct hostapd_bss_config *bss = hapd->conf; 323281806Srpaulo 324281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration"); 325281806Srpaulo 326281806Srpaulo bss->wps_state = 2; 327289549Srpaulo if (cred->ssid_len <= SSID_MAX_LEN) { 328281806Srpaulo os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len); 329281806Srpaulo bss->ssid.ssid_len = cred->ssid_len; 330281806Srpaulo bss->ssid.ssid_set = 1; 331281806Srpaulo } 332281806Srpaulo 333281806Srpaulo if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) && 334281806Srpaulo (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))) 335281806Srpaulo bss->wpa = 3; 336281806Srpaulo else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) 337281806Srpaulo bss->wpa = 2; 338281806Srpaulo else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)) 339281806Srpaulo bss->wpa = 1; 340281806Srpaulo else 341281806Srpaulo bss->wpa = 0; 342281806Srpaulo 343281806Srpaulo if (bss->wpa) { 344281806Srpaulo if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA)) 345281806Srpaulo bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X; 346281806Srpaulo if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) 347281806Srpaulo bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK; 348281806Srpaulo 349281806Srpaulo bss->wpa_pairwise = 0; 350289549Srpaulo if (cred->encr_type & WPS_ENCR_AES) { 351289549Srpaulo if (hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD) 352289549Srpaulo bss->wpa_pairwise |= WPA_CIPHER_GCMP; 353289549Srpaulo else 354289549Srpaulo bss->wpa_pairwise |= WPA_CIPHER_CCMP; 355289549Srpaulo } 356281806Srpaulo if (cred->encr_type & WPS_ENCR_TKIP) 357281806Srpaulo bss->wpa_pairwise |= WPA_CIPHER_TKIP; 358281806Srpaulo bss->rsn_pairwise = bss->wpa_pairwise; 359281806Srpaulo bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, 360281806Srpaulo bss->wpa_pairwise, 361281806Srpaulo bss->rsn_pairwise); 362281806Srpaulo 363281806Srpaulo if (cred->key_len >= 8 && cred->key_len < 64) { 364281806Srpaulo os_free(bss->ssid.wpa_passphrase); 365281806Srpaulo bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1); 366281806Srpaulo if (bss->ssid.wpa_passphrase) 367281806Srpaulo os_memcpy(bss->ssid.wpa_passphrase, cred->key, 368281806Srpaulo cred->key_len); 369281806Srpaulo hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk); 370281806Srpaulo } else if (cred->key_len == 64) { 371281806Srpaulo hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk); 372281806Srpaulo bss->ssid.wpa_psk = 373281806Srpaulo os_zalloc(sizeof(struct hostapd_wpa_psk)); 374281806Srpaulo if (bss->ssid.wpa_psk && 375281806Srpaulo hexstr2bin((const char *) cred->key, 376281806Srpaulo bss->ssid.wpa_psk->psk, PMK_LEN) == 0) { 377281806Srpaulo bss->ssid.wpa_psk->group = 1; 378281806Srpaulo os_free(bss->ssid.wpa_passphrase); 379281806Srpaulo bss->ssid.wpa_passphrase = NULL; 380281806Srpaulo } 381281806Srpaulo } 382281806Srpaulo bss->auth_algs = 1; 383281806Srpaulo } else { 384281806Srpaulo /* 385281806Srpaulo * WPS 2.0 does not allow WEP to be configured, so no need to 386281806Srpaulo * process that option here either. 387281806Srpaulo */ 388281806Srpaulo bss->auth_algs = 1; 389281806Srpaulo } 390281806Srpaulo 391281806Srpaulo /* Schedule configuration reload after short period of time to allow 392281806Srpaulo * EAP-WSC to be finished. 393281806Srpaulo */ 394281806Srpaulo eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface, 395281806Srpaulo NULL); 396281806Srpaulo 397281806Srpaulo return 0; 398281806Srpaulo} 399281806Srpaulo 400281806Srpaulo 401252726Srpaulostatic int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx) 402252726Srpaulo{ 403252726Srpaulo const struct wps_credential *cred = ctx; 404214501Srpaulo FILE *oconf, *nconf; 405214501Srpaulo size_t len, i; 406214501Srpaulo char *tmp_fname; 407214501Srpaulo char buf[1024]; 408214501Srpaulo int multi_bss; 409214501Srpaulo int wpa; 410214501Srpaulo 411252726Srpaulo if (hapd->wps == NULL) 412252726Srpaulo return 0; 413252726Srpaulo 414214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute", 415214501Srpaulo cred->cred_attr, cred->cred_attr_len); 416214501Srpaulo 417214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Received new AP Settings"); 418214501Srpaulo wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len); 419214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x", 420214501Srpaulo cred->auth_type); 421214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type); 422214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx); 423214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", 424214501Srpaulo cred->key, cred->key_len); 425214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, 426214501Srpaulo MAC2STR(cred->mac_addr)); 427214501Srpaulo 428214501Srpaulo if ((hapd->conf->wps_cred_processing == 1 || 429214501Srpaulo hapd->conf->wps_cred_processing == 2) && cred->cred_attr) { 430252726Srpaulo hapd_new_ap_event(hapd, cred->cred_attr, cred->cred_attr_len); 431252726Srpaulo } else if (hapd->conf->wps_cred_processing == 1 || 432252726Srpaulo hapd->conf->wps_cred_processing == 2) { 433252726Srpaulo struct wpabuf *attr; 434252726Srpaulo attr = wpabuf_alloc(200); 435252726Srpaulo if (attr && wps_build_credential_wrap(attr, cred) == 0) 436252726Srpaulo hapd_new_ap_event(hapd, wpabuf_head_u8(attr), 437252726Srpaulo wpabuf_len(attr)); 438252726Srpaulo wpabuf_free(attr); 439214501Srpaulo } else 440214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS); 441214501Srpaulo 442214501Srpaulo if (hapd->conf->wps_cred_processing == 1) 443214501Srpaulo return 0; 444214501Srpaulo 445214501Srpaulo os_memcpy(hapd->wps->ssid, cred->ssid, cred->ssid_len); 446214501Srpaulo hapd->wps->ssid_len = cred->ssid_len; 447214501Srpaulo hapd->wps->encr_types = cred->encr_type; 448214501Srpaulo hapd->wps->auth_types = cred->auth_type; 449281806Srpaulo hapd->wps->ap_encr_type = cred->encr_type; 450281806Srpaulo hapd->wps->ap_auth_type = cred->auth_type; 451214501Srpaulo if (cred->key_len == 0) { 452214501Srpaulo os_free(hapd->wps->network_key); 453214501Srpaulo hapd->wps->network_key = NULL; 454214501Srpaulo hapd->wps->network_key_len = 0; 455289549Srpaulo } else if ((cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) && 456289549Srpaulo (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN)) { 457289549Srpaulo wpa_printf(MSG_INFO, "WPS: Invalid key length %lu for WPA/WPA2", 458289549Srpaulo (unsigned long) cred->key_len); 459289549Srpaulo return -1; 460214501Srpaulo } else { 461214501Srpaulo if (hapd->wps->network_key == NULL || 462214501Srpaulo hapd->wps->network_key_len < cred->key_len) { 463214501Srpaulo hapd->wps->network_key_len = 0; 464214501Srpaulo os_free(hapd->wps->network_key); 465214501Srpaulo hapd->wps->network_key = os_malloc(cred->key_len); 466214501Srpaulo if (hapd->wps->network_key == NULL) 467214501Srpaulo return -1; 468214501Srpaulo } 469214501Srpaulo hapd->wps->network_key_len = cred->key_len; 470214501Srpaulo os_memcpy(hapd->wps->network_key, cred->key, cred->key_len); 471214501Srpaulo } 472214501Srpaulo hapd->wps->wps_state = WPS_STATE_CONFIGURED; 473214501Srpaulo 474252726Srpaulo if (hapd->iface->config_fname == NULL) 475281806Srpaulo return hapd_wps_reconfig_in_memory(hapd, cred); 476214501Srpaulo len = os_strlen(hapd->iface->config_fname) + 5; 477214501Srpaulo tmp_fname = os_malloc(len); 478214501Srpaulo if (tmp_fname == NULL) 479214501Srpaulo return -1; 480214501Srpaulo os_snprintf(tmp_fname, len, "%s-new", hapd->iface->config_fname); 481214501Srpaulo 482214501Srpaulo oconf = fopen(hapd->iface->config_fname, "r"); 483214501Srpaulo if (oconf == NULL) { 484214501Srpaulo wpa_printf(MSG_WARNING, "WPS: Could not open current " 485214501Srpaulo "configuration file"); 486214501Srpaulo os_free(tmp_fname); 487214501Srpaulo return -1; 488214501Srpaulo } 489214501Srpaulo 490214501Srpaulo nconf = fopen(tmp_fname, "w"); 491214501Srpaulo if (nconf == NULL) { 492214501Srpaulo wpa_printf(MSG_WARNING, "WPS: Could not write updated " 493214501Srpaulo "configuration file"); 494214501Srpaulo os_free(tmp_fname); 495214501Srpaulo fclose(oconf); 496214501Srpaulo return -1; 497214501Srpaulo } 498214501Srpaulo 499214501Srpaulo fprintf(nconf, "# WPS configuration - START\n"); 500214501Srpaulo 501214501Srpaulo fprintf(nconf, "wps_state=2\n"); 502214501Srpaulo 503252726Srpaulo if (is_hex(cred->ssid, cred->ssid_len)) { 504252726Srpaulo fprintf(nconf, "ssid2="); 505252726Srpaulo for (i = 0; i < cred->ssid_len; i++) 506252726Srpaulo fprintf(nconf, "%02x", cred->ssid[i]); 507252726Srpaulo fprintf(nconf, "\n"); 508252726Srpaulo } else { 509252726Srpaulo fprintf(nconf, "ssid="); 510252726Srpaulo for (i = 0; i < cred->ssid_len; i++) 511252726Srpaulo fputc(cred->ssid[i], nconf); 512252726Srpaulo fprintf(nconf, "\n"); 513252726Srpaulo } 514214501Srpaulo 515214501Srpaulo if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) && 516214501Srpaulo (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))) 517214501Srpaulo wpa = 3; 518214501Srpaulo else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) 519214501Srpaulo wpa = 2; 520214501Srpaulo else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)) 521214501Srpaulo wpa = 1; 522214501Srpaulo else 523214501Srpaulo wpa = 0; 524214501Srpaulo 525214501Srpaulo if (wpa) { 526214501Srpaulo char *prefix; 527214501Srpaulo fprintf(nconf, "wpa=%d\n", wpa); 528214501Srpaulo 529214501Srpaulo fprintf(nconf, "wpa_key_mgmt="); 530214501Srpaulo prefix = ""; 531214501Srpaulo if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA)) { 532214501Srpaulo fprintf(nconf, "WPA-EAP"); 533214501Srpaulo prefix = " "; 534214501Srpaulo } 535214501Srpaulo if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) 536214501Srpaulo fprintf(nconf, "%sWPA-PSK", prefix); 537214501Srpaulo fprintf(nconf, "\n"); 538214501Srpaulo 539214501Srpaulo fprintf(nconf, "wpa_pairwise="); 540214501Srpaulo prefix = ""; 541214501Srpaulo if (cred->encr_type & WPS_ENCR_AES) { 542289549Srpaulo if (hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD) 543289549Srpaulo fprintf(nconf, "GCMP"); 544289549Srpaulo else 545289549Srpaulo fprintf(nconf, "CCMP"); 546289549Srpaulo 547214501Srpaulo prefix = " "; 548214501Srpaulo } 549214501Srpaulo if (cred->encr_type & WPS_ENCR_TKIP) { 550214501Srpaulo fprintf(nconf, "%sTKIP", prefix); 551214501Srpaulo } 552214501Srpaulo fprintf(nconf, "\n"); 553214501Srpaulo 554214501Srpaulo if (cred->key_len >= 8 && cred->key_len < 64) { 555214501Srpaulo fprintf(nconf, "wpa_passphrase="); 556214501Srpaulo for (i = 0; i < cred->key_len; i++) 557214501Srpaulo fputc(cred->key[i], nconf); 558214501Srpaulo fprintf(nconf, "\n"); 559214501Srpaulo } else if (cred->key_len == 64) { 560214501Srpaulo fprintf(nconf, "wpa_psk="); 561214501Srpaulo for (i = 0; i < cred->key_len; i++) 562214501Srpaulo fputc(cred->key[i], nconf); 563214501Srpaulo fprintf(nconf, "\n"); 564214501Srpaulo } else { 565214501Srpaulo wpa_printf(MSG_WARNING, "WPS: Invalid key length %lu " 566214501Srpaulo "for WPA/WPA2", 567214501Srpaulo (unsigned long) cred->key_len); 568214501Srpaulo } 569214501Srpaulo 570214501Srpaulo fprintf(nconf, "auth_algs=1\n"); 571214501Srpaulo } else { 572281806Srpaulo /* 573281806Srpaulo * WPS 2.0 does not allow WEP to be configured, so no need to 574281806Srpaulo * process that option here either. 575281806Srpaulo */ 576281806Srpaulo fprintf(nconf, "auth_algs=1\n"); 577214501Srpaulo } 578214501Srpaulo 579214501Srpaulo fprintf(nconf, "# WPS configuration - END\n"); 580214501Srpaulo 581214501Srpaulo multi_bss = 0; 582214501Srpaulo while (fgets(buf, sizeof(buf), oconf)) { 583214501Srpaulo if (os_strncmp(buf, "bss=", 4) == 0) 584214501Srpaulo multi_bss = 1; 585214501Srpaulo if (!multi_bss && 586214501Srpaulo (str_starts(buf, "ssid=") || 587252726Srpaulo str_starts(buf, "ssid2=") || 588214501Srpaulo str_starts(buf, "auth_algs=") || 589252726Srpaulo str_starts(buf, "wep_default_key=") || 590252726Srpaulo str_starts(buf, "wep_key") || 591214501Srpaulo str_starts(buf, "wps_state=") || 592214501Srpaulo str_starts(buf, "wpa=") || 593214501Srpaulo str_starts(buf, "wpa_psk=") || 594214501Srpaulo str_starts(buf, "wpa_pairwise=") || 595214501Srpaulo str_starts(buf, "rsn_pairwise=") || 596214501Srpaulo str_starts(buf, "wpa_key_mgmt=") || 597214501Srpaulo str_starts(buf, "wpa_passphrase="))) { 598214501Srpaulo fprintf(nconf, "#WPS# %s", buf); 599214501Srpaulo } else 600214501Srpaulo fprintf(nconf, "%s", buf); 601214501Srpaulo } 602214501Srpaulo 603214501Srpaulo fclose(nconf); 604214501Srpaulo fclose(oconf); 605214501Srpaulo 606214501Srpaulo if (rename(tmp_fname, hapd->iface->config_fname) < 0) { 607214501Srpaulo wpa_printf(MSG_WARNING, "WPS: Failed to rename the updated " 608214501Srpaulo "configuration file: %s", strerror(errno)); 609214501Srpaulo os_free(tmp_fname); 610214501Srpaulo return -1; 611214501Srpaulo } 612214501Srpaulo 613214501Srpaulo os_free(tmp_fname); 614214501Srpaulo 615214501Srpaulo /* Schedule configuration reload after short period of time to allow 616214501Srpaulo * EAP-WSC to be finished. 617214501Srpaulo */ 618214501Srpaulo eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface, 619214501Srpaulo NULL); 620214501Srpaulo 621214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: AP configuration updated"); 622214501Srpaulo 623214501Srpaulo return 0; 624214501Srpaulo} 625214501Srpaulo 626214501Srpaulo 627252726Srpaulostatic int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred) 628252726Srpaulo{ 629252726Srpaulo struct hostapd_data *hapd = ctx; 630252726Srpaulo return hostapd_wps_for_each(hapd, hapd_wps_cred_cb, (void *) cred); 631252726Srpaulo} 632252726Srpaulo 633252726Srpaulo 634214501Srpaulostatic void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx) 635214501Srpaulo{ 636214501Srpaulo struct hostapd_data *hapd = eloop_data; 637214501Srpaulo 638214501Srpaulo if (hapd->conf->ap_setup_locked) 639214501Srpaulo return; 640252726Srpaulo if (hapd->ap_pin_failures_consecutive >= 10) 641252726Srpaulo return; 642214501Srpaulo 643214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Re-enable AP PIN"); 644214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED); 645214501Srpaulo hapd->wps->ap_setup_locked = 0; 646214501Srpaulo wps_registrar_update_ie(hapd->wps->registrar); 647214501Srpaulo} 648214501Srpaulo 649214501Srpaulo 650252726Srpaulostatic int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx) 651214501Srpaulo{ 652252726Srpaulo struct wps_event_pwd_auth_fail *data = ctx; 653214501Srpaulo 654252726Srpaulo if (!data->enrollee || hapd->conf->ap_pin == NULL || hapd->wps == NULL) 655252726Srpaulo return 0; 656252726Srpaulo 657214501Srpaulo /* 658214501Srpaulo * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup 659214501Srpaulo * for some time if this happens multiple times to slow down brute 660214501Srpaulo * force attacks. 661214501Srpaulo */ 662214501Srpaulo hapd->ap_pin_failures++; 663252726Srpaulo hapd->ap_pin_failures_consecutive++; 664252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u " 665252726Srpaulo "(%u consecutive)", 666252726Srpaulo hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive); 667214501Srpaulo if (hapd->ap_pin_failures < 3) 668252726Srpaulo return 0; 669214501Srpaulo 670214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED); 671214501Srpaulo hapd->wps->ap_setup_locked = 1; 672214501Srpaulo 673214501Srpaulo wps_registrar_update_ie(hapd->wps->registrar); 674214501Srpaulo 675252726Srpaulo if (!hapd->conf->ap_setup_locked && 676252726Srpaulo hapd->ap_pin_failures_consecutive >= 10) { 677252726Srpaulo /* 678252726Srpaulo * In indefinite lockdown - disable automatic AP PIN 679252726Srpaulo * reenablement. 680252726Srpaulo */ 681252726Srpaulo eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); 682252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: AP PIN disabled indefinitely"); 683252726Srpaulo } else if (!hapd->conf->ap_setup_locked) { 684214501Srpaulo if (hapd->ap_pin_lockout_time == 0) 685214501Srpaulo hapd->ap_pin_lockout_time = 60; 686214501Srpaulo else if (hapd->ap_pin_lockout_time < 365 * 24 * 60 * 60 && 687214501Srpaulo (hapd->ap_pin_failures % 3) == 0) 688214501Srpaulo hapd->ap_pin_lockout_time *= 2; 689214501Srpaulo 690214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN for %u seconds", 691214501Srpaulo hapd->ap_pin_lockout_time); 692214501Srpaulo eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); 693214501Srpaulo eloop_register_timeout(hapd->ap_pin_lockout_time, 0, 694214501Srpaulo hostapd_wps_reenable_ap_pin, hapd, 695214501Srpaulo NULL); 696214501Srpaulo } 697214501Srpaulo 698252726Srpaulo return 0; 699214501Srpaulo} 700214501Srpaulo 701214501Srpaulo 702252726Srpaulostatic void hostapd_pwd_auth_fail(struct hostapd_data *hapd, 703252726Srpaulo struct wps_event_pwd_auth_fail *data) 704252726Srpaulo{ 705281806Srpaulo /* Update WPS Status - Authentication Failure */ 706281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: Authentication failure update"); 707281806Srpaulo hapd->wps_stats.status = WPS_STATUS_FAILURE; 708281806Srpaulo hapd->wps_stats.failure_reason = WPS_EI_AUTH_FAILURE; 709281806Srpaulo os_memcpy(hapd->wps_stats.peer_addr, data->peer_macaddr, ETH_ALEN); 710281806Srpaulo 711252726Srpaulo hostapd_wps_for_each(hapd, wps_pwd_auth_fail, data); 712252726Srpaulo} 713252726Srpaulo 714252726Srpaulo 715252726Srpaulostatic int wps_ap_pin_success(struct hostapd_data *hapd, void *ctx) 716252726Srpaulo{ 717252726Srpaulo if (hapd->conf->ap_pin == NULL || hapd->wps == NULL) 718252726Srpaulo return 0; 719252726Srpaulo 720252726Srpaulo if (hapd->ap_pin_failures_consecutive == 0) 721252726Srpaulo return 0; 722252726Srpaulo 723252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Clear consecutive AP PIN failure counter " 724252726Srpaulo "- total validation failures %u (%u consecutive)", 725252726Srpaulo hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive); 726252726Srpaulo hapd->ap_pin_failures_consecutive = 0; 727252726Srpaulo 728252726Srpaulo return 0; 729252726Srpaulo} 730252726Srpaulo 731252726Srpaulo 732252726Srpaulostatic void hostapd_wps_ap_pin_success(struct hostapd_data *hapd) 733252726Srpaulo{ 734252726Srpaulo hostapd_wps_for_each(hapd, wps_ap_pin_success, NULL); 735252726Srpaulo} 736252726Srpaulo 737252726Srpaulo 738281806Srpaulostatic void hostapd_wps_event_pbc_overlap(struct hostapd_data *hapd) 739281806Srpaulo{ 740281806Srpaulo /* Update WPS Status - PBC Overlap */ 741281806Srpaulo hapd->wps_stats.pbc_status = WPS_PBC_STATUS_OVERLAP; 742281806Srpaulo} 743252726Srpaulo 744281806Srpaulo 745281806Srpaulostatic void hostapd_wps_event_pbc_timeout(struct hostapd_data *hapd) 746281806Srpaulo{ 747281806Srpaulo /* Update WPS PBC Status:PBC Timeout */ 748281806Srpaulo hapd->wps_stats.pbc_status = WPS_PBC_STATUS_TIMEOUT; 749281806Srpaulo} 750281806Srpaulo 751281806Srpaulo 752281806Srpaulostatic void hostapd_wps_event_pbc_active(struct hostapd_data *hapd) 753281806Srpaulo{ 754281806Srpaulo /* Update WPS PBC status - Active */ 755281806Srpaulo hapd->wps_stats.pbc_status = WPS_PBC_STATUS_ACTIVE; 756281806Srpaulo} 757281806Srpaulo 758281806Srpaulo 759281806Srpaulostatic void hostapd_wps_event_pbc_disable(struct hostapd_data *hapd) 760281806Srpaulo{ 761281806Srpaulo /* Update WPS PBC status - Active */ 762281806Srpaulo hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE; 763281806Srpaulo} 764281806Srpaulo 765281806Srpaulo 766281806Srpaulostatic void hostapd_wps_event_success(struct hostapd_data *hapd, 767281806Srpaulo struct wps_event_success *success) 768281806Srpaulo{ 769281806Srpaulo /* Update WPS status - Success */ 770281806Srpaulo hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE; 771281806Srpaulo hapd->wps_stats.status = WPS_STATUS_SUCCESS; 772281806Srpaulo os_memcpy(hapd->wps_stats.peer_addr, success->peer_macaddr, ETH_ALEN); 773281806Srpaulo} 774281806Srpaulo 775281806Srpaulo 776252726Srpaulostatic void hostapd_wps_event_fail(struct hostapd_data *hapd, 777252726Srpaulo struct wps_event_fail *fail) 778252726Srpaulo{ 779281806Srpaulo /* Update WPS status - Failure */ 780281806Srpaulo hapd->wps_stats.status = WPS_STATUS_FAILURE; 781281806Srpaulo os_memcpy(hapd->wps_stats.peer_addr, fail->peer_macaddr, ETH_ALEN); 782281806Srpaulo 783281806Srpaulo hapd->wps_stats.failure_reason = fail->error_indication; 784281806Srpaulo 785252726Srpaulo if (fail->error_indication > 0 && 786252726Srpaulo fail->error_indication < NUM_WPS_EI_VALUES) { 787252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, 788252726Srpaulo WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)", 789252726Srpaulo fail->msg, fail->config_error, fail->error_indication, 790281806Srpaulo wps_ei_str(fail->error_indication)); 791252726Srpaulo } else { 792252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, 793252726Srpaulo WPS_EVENT_FAIL "msg=%d config_error=%d", 794252726Srpaulo fail->msg, fail->config_error); 795252726Srpaulo } 796252726Srpaulo} 797252726Srpaulo 798252726Srpaulo 799214501Srpaulostatic void hostapd_wps_event_cb(void *ctx, enum wps_event event, 800214501Srpaulo union wps_event_data *data) 801214501Srpaulo{ 802214501Srpaulo struct hostapd_data *hapd = ctx; 803214501Srpaulo 804252726Srpaulo switch (event) { 805252726Srpaulo case WPS_EV_M2D: 806252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_M2D); 807252726Srpaulo break; 808252726Srpaulo case WPS_EV_FAIL: 809252726Srpaulo hostapd_wps_event_fail(hapd, &data->fail); 810252726Srpaulo break; 811252726Srpaulo case WPS_EV_SUCCESS: 812281806Srpaulo hostapd_wps_event_success(hapd, &data->success); 813252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS); 814252726Srpaulo break; 815252726Srpaulo case WPS_EV_PWD_AUTH_FAIL: 816214501Srpaulo hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail); 817252726Srpaulo break; 818252726Srpaulo case WPS_EV_PBC_OVERLAP: 819281806Srpaulo hostapd_wps_event_pbc_overlap(hapd); 820252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP); 821252726Srpaulo break; 822252726Srpaulo case WPS_EV_PBC_TIMEOUT: 823281806Srpaulo hostapd_wps_event_pbc_timeout(hapd); 824252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT); 825252726Srpaulo break; 826281806Srpaulo case WPS_EV_PBC_ACTIVE: 827281806Srpaulo hostapd_wps_event_pbc_active(hapd); 828281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ACTIVE); 829281806Srpaulo break; 830281806Srpaulo case WPS_EV_PBC_DISABLE: 831281806Srpaulo hostapd_wps_event_pbc_disable(hapd); 832281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_DISABLE); 833281806Srpaulo break; 834252726Srpaulo case WPS_EV_ER_AP_ADD: 835252726Srpaulo break; 836252726Srpaulo case WPS_EV_ER_AP_REMOVE: 837252726Srpaulo break; 838252726Srpaulo case WPS_EV_ER_ENROLLEE_ADD: 839252726Srpaulo break; 840252726Srpaulo case WPS_EV_ER_ENROLLEE_REMOVE: 841252726Srpaulo break; 842252726Srpaulo case WPS_EV_ER_AP_SETTINGS: 843252726Srpaulo break; 844252726Srpaulo case WPS_EV_ER_SET_SELECTED_REGISTRAR: 845252726Srpaulo break; 846252726Srpaulo case WPS_EV_AP_PIN_SUCCESS: 847252726Srpaulo hostapd_wps_ap_pin_success(hapd); 848252726Srpaulo break; 849252726Srpaulo } 850252726Srpaulo if (hapd->wps_event_cb) 851252726Srpaulo hapd->wps_event_cb(hapd->wps_event_cb_ctx, event, data); 852214501Srpaulo} 853214501Srpaulo 854214501Srpaulo 855281806Srpaulostatic int hostapd_wps_rf_band_cb(void *ctx) 856214501Srpaulo{ 857281806Srpaulo struct hostapd_data *hapd = ctx; 858281806Srpaulo 859281806Srpaulo return hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ? 860289549Srpaulo WPS_RF_50GHZ : 861289549Srpaulo hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD ? 862289549Srpaulo WPS_RF_60GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */ 863281806Srpaulo} 864281806Srpaulo 865281806Srpaulo 866281806Srpaulostatic void hostapd_wps_clear_ies(struct hostapd_data *hapd, int deinit_only) 867281806Srpaulo{ 868214501Srpaulo wpabuf_free(hapd->wps_beacon_ie); 869214501Srpaulo hapd->wps_beacon_ie = NULL; 870214501Srpaulo 871214501Srpaulo wpabuf_free(hapd->wps_probe_resp_ie); 872214501Srpaulo hapd->wps_probe_resp_ie = NULL; 873214501Srpaulo 874289549Srpaulo if (deinit_only) { 875289549Srpaulo hostapd_reset_ap_wps_ie(hapd); 876281806Srpaulo return; 877289549Srpaulo } 878281806Srpaulo 879252726Srpaulo hostapd_set_ap_wps_ie(hapd); 880214501Srpaulo} 881214501Srpaulo 882214501Srpaulo 883252726Srpaulostatic int get_uuid_cb(struct hostapd_iface *iface, void *ctx) 884252726Srpaulo{ 885252726Srpaulo const u8 **uuid = ctx; 886252726Srpaulo size_t j; 887252726Srpaulo 888252726Srpaulo if (iface == NULL) 889252726Srpaulo return 0; 890252726Srpaulo for (j = 0; j < iface->num_bss; j++) { 891252726Srpaulo struct hostapd_data *hapd = iface->bss[j]; 892281806Srpaulo if (hapd->wps && !hapd->conf->wps_independent && 893281806Srpaulo !is_nil_uuid(hapd->wps->uuid)) { 894252726Srpaulo *uuid = hapd->wps->uuid; 895252726Srpaulo return 1; 896252726Srpaulo } 897252726Srpaulo } 898252726Srpaulo 899252726Srpaulo return 0; 900252726Srpaulo} 901252726Srpaulo 902252726Srpaulo 903252726Srpaulostatic const u8 * get_own_uuid(struct hostapd_iface *iface) 904252726Srpaulo{ 905252726Srpaulo const u8 *uuid; 906252726Srpaulo if (iface->interfaces == NULL || 907252726Srpaulo iface->interfaces->for_each_interface == NULL) 908252726Srpaulo return NULL; 909252726Srpaulo uuid = NULL; 910252726Srpaulo iface->interfaces->for_each_interface(iface->interfaces, get_uuid_cb, 911252726Srpaulo &uuid); 912252726Srpaulo return uuid; 913252726Srpaulo} 914252726Srpaulo 915252726Srpaulo 916252726Srpaulostatic int count_interface_cb(struct hostapd_iface *iface, void *ctx) 917252726Srpaulo{ 918252726Srpaulo int *count= ctx; 919252726Srpaulo (*count)++; 920252726Srpaulo return 0; 921252726Srpaulo} 922252726Srpaulo 923252726Srpaulo 924252726Srpaulostatic int interface_count(struct hostapd_iface *iface) 925252726Srpaulo{ 926252726Srpaulo int count = 0; 927252726Srpaulo if (iface->interfaces == NULL || 928252726Srpaulo iface->interfaces->for_each_interface == NULL) 929252726Srpaulo return 0; 930252726Srpaulo iface->interfaces->for_each_interface(iface->interfaces, 931252726Srpaulo count_interface_cb, &count); 932252726Srpaulo return count; 933252726Srpaulo} 934252726Srpaulo 935252726Srpaulo 936252726Srpaulostatic int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd, 937252726Srpaulo struct wps_context *wps) 938252726Srpaulo{ 939252726Srpaulo int i; 940252726Srpaulo 941252726Srpaulo for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { 942252726Srpaulo wpabuf_free(wps->dev.vendor_ext[i]); 943252726Srpaulo wps->dev.vendor_ext[i] = NULL; 944252726Srpaulo 945252726Srpaulo if (hapd->conf->wps_vendor_ext[i] == NULL) 946252726Srpaulo continue; 947252726Srpaulo 948252726Srpaulo wps->dev.vendor_ext[i] = 949252726Srpaulo wpabuf_dup(hapd->conf->wps_vendor_ext[i]); 950252726Srpaulo if (wps->dev.vendor_ext[i] == NULL) { 951252726Srpaulo while (--i >= 0) 952252726Srpaulo wpabuf_free(wps->dev.vendor_ext[i]); 953252726Srpaulo return -1; 954252726Srpaulo } 955252726Srpaulo } 956252726Srpaulo 957252726Srpaulo return 0; 958252726Srpaulo} 959252726Srpaulo 960252726Srpaulo 961281806Srpaulostatic void hostapd_free_wps(struct wps_context *wps) 962281806Srpaulo{ 963281806Srpaulo int i; 964281806Srpaulo 965281806Srpaulo for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) 966281806Srpaulo wpabuf_free(wps->dev.vendor_ext[i]); 967281806Srpaulo wps_device_data_free(&wps->dev); 968281806Srpaulo os_free(wps->network_key); 969281806Srpaulo hostapd_wps_nfc_clear(wps); 970281806Srpaulo wpabuf_free(wps->dh_pubkey); 971281806Srpaulo wpabuf_free(wps->dh_privkey); 972281806Srpaulo os_free(wps); 973281806Srpaulo} 974281806Srpaulo 975281806Srpaulo 976214501Srpauloint hostapd_init_wps(struct hostapd_data *hapd, 977214501Srpaulo struct hostapd_bss_config *conf) 978214501Srpaulo{ 979214501Srpaulo struct wps_context *wps; 980214501Srpaulo struct wps_registrar_config cfg; 981214501Srpaulo 982214501Srpaulo if (conf->wps_state == 0) { 983281806Srpaulo hostapd_wps_clear_ies(hapd, 0); 984214501Srpaulo return 0; 985214501Srpaulo } 986214501Srpaulo 987214501Srpaulo wps = os_zalloc(sizeof(*wps)); 988214501Srpaulo if (wps == NULL) 989214501Srpaulo return -1; 990214501Srpaulo 991214501Srpaulo wps->cred_cb = hostapd_wps_cred_cb; 992214501Srpaulo wps->event_cb = hostapd_wps_event_cb; 993281806Srpaulo wps->rf_band_cb = hostapd_wps_rf_band_cb; 994214501Srpaulo wps->cb_ctx = hapd; 995214501Srpaulo 996214501Srpaulo os_memset(&cfg, 0, sizeof(cfg)); 997214501Srpaulo wps->wps_state = hapd->conf->wps_state; 998214501Srpaulo wps->ap_setup_locked = hapd->conf->ap_setup_locked; 999214501Srpaulo if (is_nil_uuid(hapd->conf->uuid)) { 1000252726Srpaulo const u8 *uuid; 1001252726Srpaulo uuid = get_own_uuid(hapd->iface); 1002281806Srpaulo if (uuid && !conf->wps_independent) { 1003252726Srpaulo os_memcpy(wps->uuid, uuid, UUID_LEN); 1004252726Srpaulo wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another " 1005252726Srpaulo "interface", wps->uuid, UUID_LEN); 1006252726Srpaulo } else { 1007252726Srpaulo uuid_gen_mac_addr(hapd->own_addr, wps->uuid); 1008252726Srpaulo wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC " 1009252726Srpaulo "address", wps->uuid, UUID_LEN); 1010252726Srpaulo } 1011252726Srpaulo } else { 1012252726Srpaulo os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN); 1013252726Srpaulo wpa_hexdump(MSG_DEBUG, "WPS: Use configured UUID", 1014214501Srpaulo wps->uuid, UUID_LEN); 1015252726Srpaulo } 1016214501Srpaulo wps->ssid_len = hapd->conf->ssid.ssid_len; 1017214501Srpaulo os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len); 1018214501Srpaulo wps->ap = 1; 1019214501Srpaulo os_memcpy(wps->dev.mac_addr, hapd->own_addr, ETH_ALEN); 1020214501Srpaulo wps->dev.device_name = hapd->conf->device_name ? 1021214501Srpaulo os_strdup(hapd->conf->device_name) : NULL; 1022214501Srpaulo wps->dev.manufacturer = hapd->conf->manufacturer ? 1023214501Srpaulo os_strdup(hapd->conf->manufacturer) : NULL; 1024214501Srpaulo wps->dev.model_name = hapd->conf->model_name ? 1025214501Srpaulo os_strdup(hapd->conf->model_name) : NULL; 1026214501Srpaulo wps->dev.model_number = hapd->conf->model_number ? 1027214501Srpaulo os_strdup(hapd->conf->model_number) : NULL; 1028214501Srpaulo wps->dev.serial_number = hapd->conf->serial_number ? 1029214501Srpaulo os_strdup(hapd->conf->serial_number) : NULL; 1030214501Srpaulo wps->config_methods = 1031214501Srpaulo wps_config_methods_str2bin(hapd->conf->config_methods); 1032252726Srpaulo if ((wps->config_methods & 1033252726Srpaulo (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY | 1034252726Srpaulo WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) { 1035252726Srpaulo wpa_printf(MSG_INFO, "WPS: Converting display to " 1036252726Srpaulo "virtual_display for WPS 2.0 compliance"); 1037252726Srpaulo wps->config_methods |= WPS_CONFIG_VIRT_DISPLAY; 1038252726Srpaulo } 1039252726Srpaulo if ((wps->config_methods & 1040252726Srpaulo (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON | 1041252726Srpaulo WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) { 1042252726Srpaulo wpa_printf(MSG_INFO, "WPS: Converting push_button to " 1043252726Srpaulo "virtual_push_button for WPS 2.0 compliance"); 1044252726Srpaulo wps->config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON; 1045252726Srpaulo } 1046252726Srpaulo os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type, 1047252726Srpaulo WPS_DEV_TYPE_LEN); 1048252726Srpaulo 1049281806Srpaulo if (hostapd_wps_set_vendor_ext(hapd, wps) < 0) 1050281806Srpaulo goto fail; 1051252726Srpaulo 1052214501Srpaulo wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version); 1053214501Srpaulo 1054252726Srpaulo if (conf->wps_rf_bands) { 1055252726Srpaulo wps->dev.rf_bands = conf->wps_rf_bands; 1056252726Srpaulo } else { 1057252726Srpaulo wps->dev.rf_bands = 1058252726Srpaulo hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ? 1059289549Srpaulo WPS_RF_50GHZ : 1060289549Srpaulo hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD ? 1061289549Srpaulo WPS_RF_60GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */ 1062252726Srpaulo } 1063252726Srpaulo 1064214501Srpaulo if (conf->wpa & WPA_PROTO_RSN) { 1065214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) 1066214501Srpaulo wps->auth_types |= WPS_AUTH_WPA2PSK; 1067214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) 1068214501Srpaulo wps->auth_types |= WPS_AUTH_WPA2; 1069214501Srpaulo 1070281806Srpaulo if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) 1071214501Srpaulo wps->encr_types |= WPS_ENCR_AES; 1072214501Srpaulo if (conf->rsn_pairwise & WPA_CIPHER_TKIP) 1073214501Srpaulo wps->encr_types |= WPS_ENCR_TKIP; 1074214501Srpaulo } 1075214501Srpaulo 1076214501Srpaulo if (conf->wpa & WPA_PROTO_WPA) { 1077214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) 1078214501Srpaulo wps->auth_types |= WPS_AUTH_WPAPSK; 1079214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) 1080214501Srpaulo wps->auth_types |= WPS_AUTH_WPA; 1081214501Srpaulo 1082214501Srpaulo if (conf->wpa_pairwise & WPA_CIPHER_CCMP) 1083214501Srpaulo wps->encr_types |= WPS_ENCR_AES; 1084214501Srpaulo if (conf->wpa_pairwise & WPA_CIPHER_TKIP) 1085214501Srpaulo wps->encr_types |= WPS_ENCR_TKIP; 1086214501Srpaulo } 1087214501Srpaulo 1088214501Srpaulo if (conf->ssid.security_policy == SECURITY_PLAINTEXT) { 1089214501Srpaulo wps->encr_types |= WPS_ENCR_NONE; 1090214501Srpaulo wps->auth_types |= WPS_AUTH_OPEN; 1091214501Srpaulo } 1092214501Srpaulo 1093214501Srpaulo if (conf->ssid.wpa_psk_file) { 1094214501Srpaulo /* Use per-device PSKs */ 1095214501Srpaulo } else if (conf->ssid.wpa_passphrase) { 1096214501Srpaulo wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase); 1097214501Srpaulo wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase); 1098214501Srpaulo } else if (conf->ssid.wpa_psk) { 1099214501Srpaulo wps->network_key = os_malloc(2 * PMK_LEN + 1); 1100281806Srpaulo if (wps->network_key == NULL) 1101281806Srpaulo goto fail; 1102214501Srpaulo wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1, 1103214501Srpaulo conf->ssid.wpa_psk->psk, PMK_LEN); 1104214501Srpaulo wps->network_key_len = 2 * PMK_LEN; 1105214501Srpaulo } else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) { 1106214501Srpaulo wps->network_key = os_malloc(conf->ssid.wep.len[0]); 1107281806Srpaulo if (wps->network_key == NULL) 1108281806Srpaulo goto fail; 1109214501Srpaulo os_memcpy(wps->network_key, conf->ssid.wep.key[0], 1110214501Srpaulo conf->ssid.wep.len[0]); 1111214501Srpaulo wps->network_key_len = conf->ssid.wep.len[0]; 1112214501Srpaulo } 1113214501Srpaulo 1114214501Srpaulo if (conf->ssid.wpa_psk) { 1115214501Srpaulo os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN); 1116214501Srpaulo wps->psk_set = 1; 1117214501Srpaulo } 1118214501Srpaulo 1119281806Srpaulo wps->ap_auth_type = wps->auth_types; 1120281806Srpaulo wps->ap_encr_type = wps->encr_types; 1121214501Srpaulo if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) { 1122214501Srpaulo /* Override parameters to enable security by default */ 1123214501Srpaulo wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK; 1124214501Srpaulo wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP; 1125214501Srpaulo } 1126214501Srpaulo 1127214501Srpaulo wps->ap_settings = conf->ap_settings; 1128214501Srpaulo wps->ap_settings_len = conf->ap_settings_len; 1129214501Srpaulo 1130214501Srpaulo cfg.new_psk_cb = hostapd_wps_new_psk_cb; 1131214501Srpaulo cfg.set_ie_cb = hostapd_wps_set_ie_cb; 1132214501Srpaulo cfg.pin_needed_cb = hostapd_wps_pin_needed_cb; 1133214501Srpaulo cfg.reg_success_cb = hostapd_wps_reg_success_cb; 1134214501Srpaulo cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb; 1135214501Srpaulo cfg.cb_ctx = hapd; 1136214501Srpaulo cfg.skip_cred_build = conf->skip_cred_build; 1137214501Srpaulo cfg.extra_cred = conf->extra_cred; 1138214501Srpaulo cfg.extra_cred_len = conf->extra_cred_len; 1139214501Srpaulo cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) && 1140214501Srpaulo conf->skip_cred_build; 1141214501Srpaulo if (conf->ssid.security_policy == SECURITY_STATIC_WEP) 1142214501Srpaulo cfg.static_wep_only = 1; 1143252726Srpaulo cfg.dualband = interface_count(hapd->iface) > 1; 1144252726Srpaulo if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) == 1145252726Srpaulo (WPS_RF_50GHZ | WPS_RF_24GHZ)) 1146252726Srpaulo cfg.dualband = 1; 1147252726Srpaulo if (cfg.dualband) 1148252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Dualband AP"); 1149281806Srpaulo cfg.force_per_enrollee_psk = conf->force_per_enrollee_psk; 1150214501Srpaulo 1151214501Srpaulo wps->registrar = wps_registrar_init(wps, &cfg); 1152214501Srpaulo if (wps->registrar == NULL) { 1153252726Srpaulo wpa_printf(MSG_ERROR, "Failed to initialize WPS Registrar"); 1154281806Srpaulo goto fail; 1155214501Srpaulo } 1156214501Srpaulo 1157214501Srpaulo#ifdef CONFIG_WPS_UPNP 1158214501Srpaulo wps->friendly_name = hapd->conf->friendly_name; 1159214501Srpaulo wps->manufacturer_url = hapd->conf->manufacturer_url; 1160214501Srpaulo wps->model_description = hapd->conf->model_description; 1161214501Srpaulo wps->model_url = hapd->conf->model_url; 1162214501Srpaulo wps->upc = hapd->conf->upc; 1163252726Srpaulo#endif /* CONFIG_WPS_UPNP */ 1164214501Srpaulo 1165252726Srpaulo hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd); 1166252726Srpaulo 1167252726Srpaulo hapd->wps = wps; 1168252726Srpaulo 1169252726Srpaulo return 0; 1170281806Srpaulo 1171281806Srpaulofail: 1172281806Srpaulo hostapd_free_wps(wps); 1173281806Srpaulo return -1; 1174252726Srpaulo} 1175252726Srpaulo 1176252726Srpaulo 1177252726Srpauloint hostapd_init_wps_complete(struct hostapd_data *hapd) 1178252726Srpaulo{ 1179252726Srpaulo struct wps_context *wps = hapd->wps; 1180252726Srpaulo 1181252726Srpaulo if (wps == NULL) 1182252726Srpaulo return 0; 1183252726Srpaulo 1184252726Srpaulo#ifdef CONFIG_WPS_UPNP 1185214501Srpaulo if (hostapd_wps_upnp_init(hapd, wps) < 0) { 1186214501Srpaulo wpa_printf(MSG_ERROR, "Failed to initialize WPS UPnP"); 1187214501Srpaulo wps_registrar_deinit(wps->registrar); 1188281806Srpaulo hostapd_free_wps(wps); 1189252726Srpaulo hapd->wps = NULL; 1190214501Srpaulo return -1; 1191214501Srpaulo } 1192214501Srpaulo#endif /* CONFIG_WPS_UPNP */ 1193214501Srpaulo 1194252726Srpaulo return 0; 1195252726Srpaulo} 1196214501Srpaulo 1197214501Srpaulo 1198252726Srpaulostatic void hostapd_wps_nfc_clear(struct wps_context *wps) 1199252726Srpaulo{ 1200252726Srpaulo#ifdef CONFIG_WPS_NFC 1201281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: Clear NFC Tag context %p", wps); 1202252726Srpaulo wps->ap_nfc_dev_pw_id = 0; 1203252726Srpaulo wpabuf_free(wps->ap_nfc_dh_pubkey); 1204252726Srpaulo wps->ap_nfc_dh_pubkey = NULL; 1205252726Srpaulo wpabuf_free(wps->ap_nfc_dh_privkey); 1206252726Srpaulo wps->ap_nfc_dh_privkey = NULL; 1207252726Srpaulo wpabuf_free(wps->ap_nfc_dev_pw); 1208252726Srpaulo wps->ap_nfc_dev_pw = NULL; 1209252726Srpaulo#endif /* CONFIG_WPS_NFC */ 1210214501Srpaulo} 1211214501Srpaulo 1212214501Srpaulo 1213214501Srpaulovoid hostapd_deinit_wps(struct hostapd_data *hapd) 1214214501Srpaulo{ 1215214501Srpaulo eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); 1216214501Srpaulo eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); 1217281806Srpaulo eloop_cancel_timeout(wps_reload_config, hapd->iface, NULL); 1218281806Srpaulo if (hapd->wps == NULL) { 1219281806Srpaulo hostapd_wps_clear_ies(hapd, 1); 1220214501Srpaulo return; 1221281806Srpaulo } 1222214501Srpaulo#ifdef CONFIG_WPS_UPNP 1223214501Srpaulo hostapd_wps_upnp_deinit(hapd); 1224214501Srpaulo#endif /* CONFIG_WPS_UPNP */ 1225214501Srpaulo wps_registrar_deinit(hapd->wps->registrar); 1226214501Srpaulo wps_free_pending_msgs(hapd->wps->upnp_msgs); 1227281806Srpaulo hostapd_free_wps(hapd->wps); 1228214501Srpaulo hapd->wps = NULL; 1229281806Srpaulo hostapd_wps_clear_ies(hapd, 1); 1230214501Srpaulo} 1231214501Srpaulo 1232214501Srpaulo 1233214501Srpaulovoid hostapd_update_wps(struct hostapd_data *hapd) 1234214501Srpaulo{ 1235214501Srpaulo if (hapd->wps == NULL) 1236214501Srpaulo return; 1237252726Srpaulo 1238252726Srpaulo#ifdef CONFIG_WPS_UPNP 1239252726Srpaulo hapd->wps->friendly_name = hapd->conf->friendly_name; 1240252726Srpaulo hapd->wps->manufacturer_url = hapd->conf->manufacturer_url; 1241252726Srpaulo hapd->wps->model_description = hapd->conf->model_description; 1242252726Srpaulo hapd->wps->model_url = hapd->conf->model_url; 1243252726Srpaulo hapd->wps->upc = hapd->conf->upc; 1244252726Srpaulo#endif /* CONFIG_WPS_UPNP */ 1245252726Srpaulo 1246252726Srpaulo hostapd_wps_set_vendor_ext(hapd, hapd->wps); 1247252726Srpaulo 1248214501Srpaulo if (hapd->conf->wps_state) 1249214501Srpaulo wps_registrar_update_ie(hapd->wps->registrar); 1250214501Srpaulo else 1251214501Srpaulo hostapd_deinit_wps(hapd); 1252214501Srpaulo} 1253214501Srpaulo 1254214501Srpaulo 1255252726Srpaulostruct wps_add_pin_data { 1256252726Srpaulo const u8 *addr; 1257252726Srpaulo const u8 *uuid; 1258252726Srpaulo const u8 *pin; 1259252726Srpaulo size_t pin_len; 1260252726Srpaulo int timeout; 1261252726Srpaulo int added; 1262252726Srpaulo}; 1263252726Srpaulo 1264252726Srpaulo 1265252726Srpaulostatic int wps_add_pin(struct hostapd_data *hapd, void *ctx) 1266214501Srpaulo{ 1267252726Srpaulo struct wps_add_pin_data *data = ctx; 1268252726Srpaulo int ret; 1269252726Srpaulo 1270252726Srpaulo if (hapd->wps == NULL) 1271252726Srpaulo return 0; 1272252726Srpaulo ret = wps_registrar_add_pin(hapd->wps->registrar, data->addr, 1273252726Srpaulo data->uuid, data->pin, data->pin_len, 1274252726Srpaulo data->timeout); 1275252726Srpaulo if (ret == 0) 1276252726Srpaulo data->added++; 1277252726Srpaulo return ret; 1278252726Srpaulo} 1279252726Srpaulo 1280252726Srpaulo 1281252726Srpauloint hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr, 1282252726Srpaulo const char *uuid, const char *pin, int timeout) 1283252726Srpaulo{ 1284214501Srpaulo u8 u[UUID_LEN]; 1285252726Srpaulo struct wps_add_pin_data data; 1286214501Srpaulo 1287252726Srpaulo data.addr = addr; 1288252726Srpaulo data.uuid = u; 1289252726Srpaulo data.pin = (const u8 *) pin; 1290252726Srpaulo data.pin_len = os_strlen(pin); 1291252726Srpaulo data.timeout = timeout; 1292252726Srpaulo data.added = 0; 1293252726Srpaulo 1294214501Srpaulo if (os_strcmp(uuid, "any") == 0) 1295252726Srpaulo data.uuid = NULL; 1296252726Srpaulo else { 1297252726Srpaulo if (uuid_str2bin(uuid, u)) 1298252726Srpaulo return -1; 1299252726Srpaulo data.uuid = u; 1300252726Srpaulo } 1301252726Srpaulo if (hostapd_wps_for_each(hapd, wps_add_pin, &data) < 0) 1302214501Srpaulo return -1; 1303252726Srpaulo return data.added ? 0 : -1; 1304214501Srpaulo} 1305214501Srpaulo 1306214501Srpaulo 1307289549Srpaulostruct wps_button_pushed_ctx { 1308289549Srpaulo const u8 *p2p_dev_addr; 1309289549Srpaulo unsigned int count; 1310289549Srpaulo}; 1311289549Srpaulo 1312252726Srpaulostatic int wps_button_pushed(struct hostapd_data *hapd, void *ctx) 1313214501Srpaulo{ 1314289549Srpaulo struct wps_button_pushed_ctx *data = ctx; 1315289549Srpaulo 1316289549Srpaulo if (hapd->wps) { 1317289549Srpaulo data->count++; 1318289549Srpaulo return wps_registrar_button_pushed(hapd->wps->registrar, 1319289549Srpaulo data->p2p_dev_addr); 1320289549Srpaulo } 1321289549Srpaulo 1322289549Srpaulo return 0; 1323214501Srpaulo} 1324214501Srpaulo 1325214501Srpaulo 1326252726Srpauloint hostapd_wps_button_pushed(struct hostapd_data *hapd, 1327252726Srpaulo const u8 *p2p_dev_addr) 1328214501Srpaulo{ 1329289549Srpaulo struct wps_button_pushed_ctx ctx; 1330289549Srpaulo int ret; 1331289549Srpaulo 1332289549Srpaulo os_memset(&ctx, 0, sizeof(ctx)); 1333289549Srpaulo ctx.p2p_dev_addr = p2p_dev_addr; 1334289549Srpaulo ret = hostapd_wps_for_each(hapd, wps_button_pushed, &ctx); 1335289549Srpaulo if (ret == 0 && !ctx.count) 1336289549Srpaulo ret = -1; 1337289549Srpaulo return ret; 1338252726Srpaulo} 1339214501Srpaulo 1340214501Srpaulo 1341289549Srpaulostruct wps_cancel_ctx { 1342289549Srpaulo unsigned int count; 1343289549Srpaulo}; 1344289549Srpaulo 1345252726Srpaulostatic int wps_cancel(struct hostapd_data *hapd, void *ctx) 1346252726Srpaulo{ 1347289549Srpaulo struct wps_cancel_ctx *data = ctx; 1348214501Srpaulo 1349289549Srpaulo if (hapd->wps) { 1350289549Srpaulo data->count++; 1351289549Srpaulo wps_registrar_wps_cancel(hapd->wps->registrar); 1352289549Srpaulo ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL); 1353289549Srpaulo } 1354214501Srpaulo 1355214501Srpaulo return 0; 1356252726Srpaulo} 1357214501Srpaulo 1358252726Srpaulo 1359252726Srpauloint hostapd_wps_cancel(struct hostapd_data *hapd) 1360252726Srpaulo{ 1361289549Srpaulo struct wps_cancel_ctx ctx; 1362289549Srpaulo int ret; 1363289549Srpaulo 1364289549Srpaulo os_memset(&ctx, 0, sizeof(ctx)); 1365289549Srpaulo ret = hostapd_wps_for_each(hapd, wps_cancel, &ctx); 1366289549Srpaulo if (ret == 0 && !ctx.count) 1367289549Srpaulo ret = -1; 1368289549Srpaulo return ret; 1369214501Srpaulo} 1370214501Srpaulo 1371214501Srpaulo 1372252726Srpaulostatic int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da, 1373252726Srpaulo const u8 *bssid, 1374252726Srpaulo const u8 *ie, size_t ie_len, 1375252726Srpaulo int ssi_signal) 1376214501Srpaulo{ 1377214501Srpaulo struct hostapd_data *hapd = ctx; 1378214501Srpaulo struct wpabuf *wps_ie; 1379214501Srpaulo struct ieee802_11_elems elems; 1380214501Srpaulo 1381214501Srpaulo if (hapd->wps == NULL) 1382214501Srpaulo return 0; 1383214501Srpaulo 1384214501Srpaulo if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) { 1385214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Could not parse ProbeReq from " 1386214501Srpaulo MACSTR, MAC2STR(addr)); 1387214501Srpaulo return 0; 1388214501Srpaulo } 1389214501Srpaulo 1390214501Srpaulo if (elems.ssid && elems.ssid_len > 0 && 1391214501Srpaulo (elems.ssid_len != hapd->conf->ssid.ssid_len || 1392214501Srpaulo os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) != 1393214501Srpaulo 0)) 1394214501Srpaulo return 0; /* Not for us */ 1395214501Srpaulo 1396214501Srpaulo wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA); 1397214501Srpaulo if (wps_ie == NULL) 1398214501Srpaulo return 0; 1399252726Srpaulo if (wps_validate_probe_req(wps_ie, addr) < 0) { 1400252726Srpaulo wpabuf_free(wps_ie); 1401252726Srpaulo return 0; 1402252726Srpaulo } 1403214501Srpaulo 1404214501Srpaulo if (wpabuf_len(wps_ie) > 0) { 1405252726Srpaulo int p2p_wildcard = 0; 1406252726Srpaulo#ifdef CONFIG_P2P 1407252726Srpaulo if (elems.ssid && elems.ssid_len == P2P_WILDCARD_SSID_LEN && 1408252726Srpaulo os_memcmp(elems.ssid, P2P_WILDCARD_SSID, 1409252726Srpaulo P2P_WILDCARD_SSID_LEN) == 0) 1410252726Srpaulo p2p_wildcard = 1; 1411252726Srpaulo#endif /* CONFIG_P2P */ 1412252726Srpaulo wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie, 1413252726Srpaulo p2p_wildcard); 1414214501Srpaulo#ifdef CONFIG_WPS_UPNP 1415214501Srpaulo /* FIX: what exactly should be included in the WLANEvent? 1416214501Srpaulo * WPS attributes? Full ProbeReq frame? */ 1417252726Srpaulo if (!p2p_wildcard) 1418252726Srpaulo upnp_wps_device_send_wlan_event( 1419252726Srpaulo hapd->wps_upnp, addr, 1420252726Srpaulo UPNP_WPS_WLANEVENT_TYPE_PROBE, wps_ie); 1421214501Srpaulo#endif /* CONFIG_WPS_UPNP */ 1422214501Srpaulo } 1423214501Srpaulo 1424214501Srpaulo wpabuf_free(wps_ie); 1425214501Srpaulo 1426214501Srpaulo return 0; 1427214501Srpaulo} 1428214501Srpaulo 1429214501Srpaulo 1430214501Srpaulo#ifdef CONFIG_WPS_UPNP 1431214501Srpaulo 1432214501Srpaulostatic int hostapd_rx_req_put_wlan_response( 1433214501Srpaulo void *priv, enum upnp_wps_wlanevent_type ev_type, 1434214501Srpaulo const u8 *mac_addr, const struct wpabuf *msg, 1435214501Srpaulo enum wps_msg_type msg_type) 1436214501Srpaulo{ 1437214501Srpaulo struct hostapd_data *hapd = priv; 1438214501Srpaulo struct sta_info *sta; 1439214501Srpaulo struct upnp_pending_message *p; 1440214501Srpaulo 1441214501Srpaulo wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr=" 1442214501Srpaulo MACSTR, ev_type, MAC2STR(mac_addr)); 1443214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage", 1444214501Srpaulo wpabuf_head(msg), wpabuf_len(msg)); 1445214501Srpaulo if (ev_type != UPNP_WPS_WLANEVENT_TYPE_EAP) { 1446214501Srpaulo wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored unexpected " 1447214501Srpaulo "PutWLANResponse WLANEventType %d", ev_type); 1448214501Srpaulo return -1; 1449214501Srpaulo } 1450214501Srpaulo 1451214501Srpaulo /* 1452214501Srpaulo * EAP response to ongoing to WPS Registration. Send it to EAP-WSC 1453214501Srpaulo * server implementation for delivery to the peer. 1454214501Srpaulo */ 1455214501Srpaulo 1456214501Srpaulo sta = ap_get_sta(hapd, mac_addr); 1457252726Srpaulo#ifndef CONFIG_WPS_STRICT 1458214501Srpaulo if (!sta) { 1459214501Srpaulo /* 1460214501Srpaulo * Workaround - Intel wsccmd uses bogus NewWLANEventMAC: 1461214501Srpaulo * Pick STA that is in an ongoing WPS registration without 1462214501Srpaulo * checking the MAC address. 1463214501Srpaulo */ 1464214501Srpaulo wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found based " 1465214501Srpaulo "on NewWLANEventMAC; try wildcard match"); 1466214501Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 1467214501Srpaulo if (sta->eapol_sm && (sta->flags & WLAN_STA_WPS)) 1468214501Srpaulo break; 1469214501Srpaulo } 1470214501Srpaulo } 1471252726Srpaulo#endif /* CONFIG_WPS_STRICT */ 1472214501Srpaulo 1473252726Srpaulo if (!sta || !(sta->flags & WLAN_STA_WPS)) { 1474214501Srpaulo wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found"); 1475214501Srpaulo return 0; 1476214501Srpaulo } 1477214501Srpaulo 1478281806Srpaulo if (!sta->eapol_sm) { 1479281806Srpaulo /* 1480281806Srpaulo * This can happen, e.g., if an ER sends an extra message after 1481281806Srpaulo * the station has disassociated (but not fully 1482281806Srpaulo * deauthenticated). 1483281806Srpaulo */ 1484281806Srpaulo wpa_printf(MSG_DEBUG, "WPS UPnP: Matching STA did not have EAPOL state machine initialized"); 1485281806Srpaulo return 0; 1486281806Srpaulo } 1487281806Srpaulo 1488214501Srpaulo p = os_zalloc(sizeof(*p)); 1489214501Srpaulo if (p == NULL) 1490214501Srpaulo return -1; 1491214501Srpaulo os_memcpy(p->addr, sta->addr, ETH_ALEN); 1492214501Srpaulo p->msg = wpabuf_dup(msg); 1493214501Srpaulo p->type = msg_type; 1494214501Srpaulo p->next = hapd->wps->upnp_msgs; 1495214501Srpaulo hapd->wps->upnp_msgs = p; 1496214501Srpaulo 1497214501Srpaulo return eapol_auth_eap_pending_cb(sta->eapol_sm, sta->eapol_sm->eap); 1498214501Srpaulo} 1499214501Srpaulo 1500214501Srpaulo 1501214501Srpaulostatic int hostapd_wps_upnp_init(struct hostapd_data *hapd, 1502214501Srpaulo struct wps_context *wps) 1503214501Srpaulo{ 1504214501Srpaulo struct upnp_wps_device_ctx *ctx; 1505214501Srpaulo 1506214501Srpaulo if (!hapd->conf->upnp_iface) 1507214501Srpaulo return 0; 1508214501Srpaulo ctx = os_zalloc(sizeof(*ctx)); 1509214501Srpaulo if (ctx == NULL) 1510214501Srpaulo return -1; 1511214501Srpaulo 1512214501Srpaulo ctx->rx_req_put_wlan_response = hostapd_rx_req_put_wlan_response; 1513214501Srpaulo if (hapd->conf->ap_pin) 1514214501Srpaulo ctx->ap_pin = os_strdup(hapd->conf->ap_pin); 1515214501Srpaulo 1516252726Srpaulo hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd, 1517252726Srpaulo hapd->conf->upnp_iface); 1518252726Srpaulo if (hapd->wps_upnp == NULL) 1519214501Srpaulo return -1; 1520214501Srpaulo wps->wps_upnp = hapd->wps_upnp; 1521214501Srpaulo 1522214501Srpaulo return 0; 1523214501Srpaulo} 1524214501Srpaulo 1525214501Srpaulo 1526214501Srpaulostatic void hostapd_wps_upnp_deinit(struct hostapd_data *hapd) 1527214501Srpaulo{ 1528252726Srpaulo upnp_wps_device_deinit(hapd->wps_upnp, hapd); 1529214501Srpaulo} 1530214501Srpaulo 1531214501Srpaulo#endif /* CONFIG_WPS_UPNP */ 1532214501Srpaulo 1533214501Srpaulo 1534214501Srpauloint hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr, 1535214501Srpaulo char *buf, size_t buflen) 1536214501Srpaulo{ 1537214501Srpaulo if (hapd->wps == NULL) 1538214501Srpaulo return 0; 1539214501Srpaulo return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen); 1540214501Srpaulo} 1541214501Srpaulo 1542214501Srpaulo 1543214501Srpaulostatic void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx) 1544214501Srpaulo{ 1545214501Srpaulo struct hostapd_data *hapd = eloop_data; 1546214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out"); 1547214501Srpaulo hostapd_wps_ap_pin_disable(hapd); 1548252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_PIN_DISABLED); 1549214501Srpaulo} 1550214501Srpaulo 1551214501Srpaulo 1552214501Srpaulostatic void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout) 1553214501Srpaulo{ 1554214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout); 1555214501Srpaulo hapd->ap_pin_failures = 0; 1556252726Srpaulo hapd->ap_pin_failures_consecutive = 0; 1557214501Srpaulo hapd->conf->ap_setup_locked = 0; 1558214501Srpaulo if (hapd->wps->ap_setup_locked) { 1559214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED); 1560214501Srpaulo hapd->wps->ap_setup_locked = 0; 1561214501Srpaulo wps_registrar_update_ie(hapd->wps->registrar); 1562214501Srpaulo } 1563214501Srpaulo eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); 1564214501Srpaulo if (timeout > 0) 1565214501Srpaulo eloop_register_timeout(timeout, 0, 1566214501Srpaulo hostapd_wps_ap_pin_timeout, hapd, NULL); 1567214501Srpaulo} 1568214501Srpaulo 1569214501Srpaulo 1570252726Srpaulostatic int wps_ap_pin_disable(struct hostapd_data *hapd, void *ctx) 1571214501Srpaulo{ 1572214501Srpaulo os_free(hapd->conf->ap_pin); 1573214501Srpaulo hapd->conf->ap_pin = NULL; 1574214501Srpaulo#ifdef CONFIG_WPS_UPNP 1575214501Srpaulo upnp_wps_set_ap_pin(hapd->wps_upnp, NULL); 1576214501Srpaulo#endif /* CONFIG_WPS_UPNP */ 1577214501Srpaulo eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); 1578252726Srpaulo return 0; 1579214501Srpaulo} 1580214501Srpaulo 1581214501Srpaulo 1582252726Srpaulovoid hostapd_wps_ap_pin_disable(struct hostapd_data *hapd) 1583214501Srpaulo{ 1584252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN"); 1585252726Srpaulo hostapd_wps_for_each(hapd, wps_ap_pin_disable, NULL); 1586252726Srpaulo} 1587252726Srpaulo 1588252726Srpaulo 1589252726Srpaulostruct wps_ap_pin_data { 1590214501Srpaulo char pin_txt[9]; 1591252726Srpaulo int timeout; 1592252726Srpaulo}; 1593214501Srpaulo 1594252726Srpaulo 1595252726Srpaulostatic int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx) 1596252726Srpaulo{ 1597252726Srpaulo struct wps_ap_pin_data *data = ctx; 1598289549Srpaulo 1599289549Srpaulo if (!hapd->wps) 1600289549Srpaulo return 0; 1601289549Srpaulo 1602214501Srpaulo os_free(hapd->conf->ap_pin); 1603252726Srpaulo hapd->conf->ap_pin = os_strdup(data->pin_txt); 1604214501Srpaulo#ifdef CONFIG_WPS_UPNP 1605252726Srpaulo upnp_wps_set_ap_pin(hapd->wps_upnp, data->pin_txt); 1606214501Srpaulo#endif /* CONFIG_WPS_UPNP */ 1607252726Srpaulo hostapd_wps_ap_pin_enable(hapd, data->timeout); 1608252726Srpaulo return 0; 1609252726Srpaulo} 1610252726Srpaulo 1611252726Srpaulo 1612252726Srpauloconst char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout) 1613252726Srpaulo{ 1614252726Srpaulo unsigned int pin; 1615252726Srpaulo struct wps_ap_pin_data data; 1616252726Srpaulo 1617252726Srpaulo pin = wps_generate_pin(); 1618252726Srpaulo os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin); 1619252726Srpaulo data.timeout = timeout; 1620252726Srpaulo hostapd_wps_for_each(hapd, wps_ap_pin_set, &data); 1621214501Srpaulo return hapd->conf->ap_pin; 1622214501Srpaulo} 1623214501Srpaulo 1624214501Srpaulo 1625214501Srpauloconst char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd) 1626214501Srpaulo{ 1627214501Srpaulo return hapd->conf->ap_pin; 1628214501Srpaulo} 1629214501Srpaulo 1630214501Srpaulo 1631214501Srpauloint hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin, 1632214501Srpaulo int timeout) 1633214501Srpaulo{ 1634252726Srpaulo struct wps_ap_pin_data data; 1635252726Srpaulo int ret; 1636252726Srpaulo 1637252726Srpaulo ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin); 1638281806Srpaulo if (os_snprintf_error(sizeof(data.pin_txt), ret)) 1639214501Srpaulo return -1; 1640252726Srpaulo data.timeout = timeout; 1641252726Srpaulo return hostapd_wps_for_each(hapd, wps_ap_pin_set, &data); 1642252726Srpaulo} 1643252726Srpaulo 1644252726Srpaulo 1645252726Srpaulostatic int wps_update_ie(struct hostapd_data *hapd, void *ctx) 1646252726Srpaulo{ 1647252726Srpaulo if (hapd->wps) 1648252726Srpaulo wps_registrar_update_ie(hapd->wps->registrar); 1649214501Srpaulo return 0; 1650214501Srpaulo} 1651252726Srpaulo 1652252726Srpaulo 1653252726Srpaulovoid hostapd_wps_update_ie(struct hostapd_data *hapd) 1654252726Srpaulo{ 1655252726Srpaulo hostapd_wps_for_each(hapd, wps_update_ie, NULL); 1656252726Srpaulo} 1657252726Srpaulo 1658252726Srpaulo 1659252726Srpauloint hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid, 1660252726Srpaulo const char *auth, const char *encr, const char *key) 1661252726Srpaulo{ 1662252726Srpaulo struct wps_credential cred; 1663252726Srpaulo size_t len; 1664252726Srpaulo 1665252726Srpaulo os_memset(&cred, 0, sizeof(cred)); 1666252726Srpaulo 1667252726Srpaulo len = os_strlen(ssid); 1668252726Srpaulo if ((len & 1) || len > 2 * sizeof(cred.ssid) || 1669252726Srpaulo hexstr2bin(ssid, cred.ssid, len / 2)) 1670252726Srpaulo return -1; 1671252726Srpaulo cred.ssid_len = len / 2; 1672252726Srpaulo 1673252726Srpaulo if (os_strncmp(auth, "OPEN", 4) == 0) 1674252726Srpaulo cred.auth_type = WPS_AUTH_OPEN; 1675252726Srpaulo else if (os_strncmp(auth, "WPAPSK", 6) == 0) 1676252726Srpaulo cred.auth_type = WPS_AUTH_WPAPSK; 1677252726Srpaulo else if (os_strncmp(auth, "WPA2PSK", 7) == 0) 1678252726Srpaulo cred.auth_type = WPS_AUTH_WPA2PSK; 1679252726Srpaulo else 1680252726Srpaulo return -1; 1681252726Srpaulo 1682252726Srpaulo if (encr) { 1683252726Srpaulo if (os_strncmp(encr, "NONE", 4) == 0) 1684252726Srpaulo cred.encr_type = WPS_ENCR_NONE; 1685252726Srpaulo else if (os_strncmp(encr, "TKIP", 4) == 0) 1686252726Srpaulo cred.encr_type = WPS_ENCR_TKIP; 1687252726Srpaulo else if (os_strncmp(encr, "CCMP", 4) == 0) 1688252726Srpaulo cred.encr_type = WPS_ENCR_AES; 1689252726Srpaulo else 1690252726Srpaulo return -1; 1691252726Srpaulo } else 1692252726Srpaulo cred.encr_type = WPS_ENCR_NONE; 1693252726Srpaulo 1694252726Srpaulo if (key) { 1695252726Srpaulo len = os_strlen(key); 1696252726Srpaulo if ((len & 1) || len > 2 * sizeof(cred.key) || 1697252726Srpaulo hexstr2bin(key, cred.key, len / 2)) 1698252726Srpaulo return -1; 1699252726Srpaulo cred.key_len = len / 2; 1700252726Srpaulo } 1701252726Srpaulo 1702252726Srpaulo return wps_registrar_config_ap(hapd->wps->registrar, &cred); 1703252726Srpaulo} 1704252726Srpaulo 1705252726Srpaulo 1706252726Srpaulo#ifdef CONFIG_WPS_NFC 1707252726Srpaulo 1708252726Srpaulostruct wps_nfc_password_token_data { 1709252726Srpaulo const u8 *oob_dev_pw; 1710252726Srpaulo size_t oob_dev_pw_len; 1711252726Srpaulo int added; 1712252726Srpaulo}; 1713252726Srpaulo 1714252726Srpaulo 1715252726Srpaulostatic int wps_add_nfc_password_token(struct hostapd_data *hapd, void *ctx) 1716252726Srpaulo{ 1717252726Srpaulo struct wps_nfc_password_token_data *data = ctx; 1718252726Srpaulo int ret; 1719252726Srpaulo 1720252726Srpaulo if (hapd->wps == NULL) 1721252726Srpaulo return 0; 1722252726Srpaulo ret = wps_registrar_add_nfc_password_token(hapd->wps->registrar, 1723252726Srpaulo data->oob_dev_pw, 1724252726Srpaulo data->oob_dev_pw_len); 1725252726Srpaulo if (ret == 0) 1726252726Srpaulo data->added++; 1727252726Srpaulo return ret; 1728252726Srpaulo} 1729252726Srpaulo 1730252726Srpaulo 1731252726Srpaulostatic int hostapd_wps_add_nfc_password_token(struct hostapd_data *hapd, 1732252726Srpaulo struct wps_parse_attr *attr) 1733252726Srpaulo{ 1734252726Srpaulo struct wps_nfc_password_token_data data; 1735252726Srpaulo 1736252726Srpaulo data.oob_dev_pw = attr->oob_dev_password; 1737252726Srpaulo data.oob_dev_pw_len = attr->oob_dev_password_len; 1738252726Srpaulo data.added = 0; 1739252726Srpaulo if (hostapd_wps_for_each(hapd, wps_add_nfc_password_token, &data) < 0) 1740252726Srpaulo return -1; 1741252726Srpaulo return data.added ? 0 : -1; 1742252726Srpaulo} 1743252726Srpaulo 1744252726Srpaulo 1745252726Srpaulostatic int hostapd_wps_nfc_tag_process(struct hostapd_data *hapd, 1746252726Srpaulo const struct wpabuf *wps) 1747252726Srpaulo{ 1748252726Srpaulo struct wps_parse_attr attr; 1749252726Srpaulo 1750252726Srpaulo wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps); 1751252726Srpaulo 1752252726Srpaulo if (wps_parse_msg(wps, &attr)) { 1753252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag"); 1754252726Srpaulo return -1; 1755252726Srpaulo } 1756252726Srpaulo 1757252726Srpaulo if (attr.oob_dev_password) 1758252726Srpaulo return hostapd_wps_add_nfc_password_token(hapd, &attr); 1759252726Srpaulo 1760252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag"); 1761252726Srpaulo return -1; 1762252726Srpaulo} 1763252726Srpaulo 1764252726Srpaulo 1765252726Srpauloint hostapd_wps_nfc_tag_read(struct hostapd_data *hapd, 1766252726Srpaulo const struct wpabuf *data) 1767252726Srpaulo{ 1768252726Srpaulo const struct wpabuf *wps = data; 1769252726Srpaulo struct wpabuf *tmp = NULL; 1770252726Srpaulo int ret; 1771252726Srpaulo 1772252726Srpaulo if (wpabuf_len(data) < 4) 1773252726Srpaulo return -1; 1774252726Srpaulo 1775252726Srpaulo if (*wpabuf_head_u8(data) != 0x10) { 1776252726Srpaulo /* Assume this contains full NDEF record */ 1777252726Srpaulo tmp = ndef_parse_wifi(data); 1778252726Srpaulo if (tmp == NULL) { 1779252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF"); 1780252726Srpaulo return -1; 1781252726Srpaulo } 1782252726Srpaulo wps = tmp; 1783252726Srpaulo } 1784252726Srpaulo 1785252726Srpaulo ret = hostapd_wps_nfc_tag_process(hapd, wps); 1786252726Srpaulo wpabuf_free(tmp); 1787252726Srpaulo return ret; 1788252726Srpaulo} 1789252726Srpaulo 1790252726Srpaulo 1791252726Srpaulostruct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd, 1792252726Srpaulo int ndef) 1793252726Srpaulo{ 1794252726Srpaulo struct wpabuf *ret; 1795252726Srpaulo 1796252726Srpaulo if (hapd->wps == NULL) 1797252726Srpaulo return NULL; 1798252726Srpaulo 1799281806Srpaulo ret = wps_get_oob_cred(hapd->wps, hostapd_wps_rf_band_cb(hapd), 1800281806Srpaulo hapd->iconf->channel); 1801252726Srpaulo if (ndef && ret) { 1802252726Srpaulo struct wpabuf *tmp; 1803252726Srpaulo tmp = ndef_build_wifi(ret); 1804252726Srpaulo wpabuf_free(ret); 1805252726Srpaulo if (tmp == NULL) 1806252726Srpaulo return NULL; 1807252726Srpaulo ret = tmp; 1808252726Srpaulo } 1809252726Srpaulo 1810252726Srpaulo return ret; 1811252726Srpaulo} 1812252726Srpaulo 1813252726Srpaulo 1814281806Srpaulostruct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef) 1815281806Srpaulo{ 1816281806Srpaulo struct wpabuf *ret; 1817281806Srpaulo 1818281806Srpaulo if (hapd->wps == NULL) 1819281806Srpaulo return NULL; 1820281806Srpaulo 1821281806Srpaulo if (hapd->conf->wps_nfc_dh_pubkey == NULL) { 1822281806Srpaulo struct wps_context *wps = hapd->wps; 1823281806Srpaulo if (wps_nfc_gen_dh(&hapd->conf->wps_nfc_dh_pubkey, 1824281806Srpaulo &hapd->conf->wps_nfc_dh_privkey) < 0) 1825281806Srpaulo return NULL; 1826281806Srpaulo hostapd_wps_nfc_clear(wps); 1827281806Srpaulo wps->ap_nfc_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER; 1828281806Srpaulo wps->ap_nfc_dh_pubkey = 1829281806Srpaulo wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey); 1830281806Srpaulo wps->ap_nfc_dh_privkey = 1831281806Srpaulo wpabuf_dup(hapd->conf->wps_nfc_dh_privkey); 1832281806Srpaulo if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey) { 1833281806Srpaulo hostapd_wps_nfc_clear(wps); 1834281806Srpaulo return NULL; 1835281806Srpaulo } 1836281806Srpaulo } 1837281806Srpaulo 1838281806Srpaulo ret = wps_build_nfc_handover_sel(hapd->wps, 1839281806Srpaulo hapd->conf->wps_nfc_dh_pubkey, 1840281806Srpaulo hapd->own_addr, hapd->iface->freq); 1841281806Srpaulo 1842281806Srpaulo if (ndef && ret) { 1843281806Srpaulo struct wpabuf *tmp; 1844281806Srpaulo tmp = ndef_build_wifi(ret); 1845281806Srpaulo wpabuf_free(ret); 1846281806Srpaulo if (tmp == NULL) 1847281806Srpaulo return NULL; 1848281806Srpaulo ret = tmp; 1849281806Srpaulo } 1850281806Srpaulo 1851281806Srpaulo return ret; 1852281806Srpaulo} 1853281806Srpaulo 1854281806Srpaulo 1855281806Srpauloint hostapd_wps_nfc_report_handover(struct hostapd_data *hapd, 1856281806Srpaulo const struct wpabuf *req, 1857281806Srpaulo const struct wpabuf *sel) 1858281806Srpaulo{ 1859281806Srpaulo struct wpabuf *wps; 1860281806Srpaulo int ret = -1; 1861281806Srpaulo u16 wsc_len; 1862281806Srpaulo const u8 *pos; 1863281806Srpaulo struct wpabuf msg; 1864281806Srpaulo struct wps_parse_attr attr; 1865281806Srpaulo u16 dev_pw_id; 1866281806Srpaulo 1867281806Srpaulo /* 1868281806Srpaulo * Enrollee/station is always initiator of the NFC connection handover, 1869281806Srpaulo * so use the request message here to find Enrollee public key hash. 1870281806Srpaulo */ 1871281806Srpaulo wps = ndef_parse_wifi(req); 1872281806Srpaulo if (wps == NULL) 1873281806Srpaulo return -1; 1874281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc " 1875281806Srpaulo "payload from NFC connection handover"); 1876281806Srpaulo wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps); 1877281806Srpaulo if (wpabuf_len(wps) < 2) { 1878281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Request " 1879281806Srpaulo "Message"); 1880281806Srpaulo goto out; 1881281806Srpaulo } 1882281806Srpaulo pos = wpabuf_head(wps); 1883281806Srpaulo wsc_len = WPA_GET_BE16(pos); 1884281806Srpaulo if (wsc_len > wpabuf_len(wps) - 2) { 1885281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) " 1886281806Srpaulo "in rt Wi-Fi Handover Request Message", wsc_len); 1887281806Srpaulo goto out; 1888281806Srpaulo } 1889281806Srpaulo pos += 2; 1890281806Srpaulo 1891281806Srpaulo wpa_hexdump(MSG_DEBUG, 1892281806Srpaulo "WPS: WSC attributes in Wi-Fi Handover Request Message", 1893281806Srpaulo pos, wsc_len); 1894281806Srpaulo if (wsc_len < wpabuf_len(wps) - 2) { 1895281806Srpaulo wpa_hexdump(MSG_DEBUG, 1896281806Srpaulo "WPS: Ignore extra data after WSC attributes", 1897281806Srpaulo pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len); 1898281806Srpaulo } 1899281806Srpaulo 1900281806Srpaulo wpabuf_set(&msg, pos, wsc_len); 1901281806Srpaulo ret = wps_parse_msg(&msg, &attr); 1902281806Srpaulo if (ret < 0) { 1903281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in " 1904281806Srpaulo "Wi-Fi Handover Request Message"); 1905281806Srpaulo goto out; 1906281806Srpaulo } 1907281806Srpaulo 1908281806Srpaulo if (attr.oob_dev_password == NULL || 1909281806Srpaulo attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) { 1910281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password " 1911281806Srpaulo "included in Wi-Fi Handover Request Message"); 1912281806Srpaulo ret = -1; 1913281806Srpaulo goto out; 1914281806Srpaulo } 1915281806Srpaulo 1916281806Srpaulo if (attr.uuid_e == NULL) { 1917281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: No UUID-E included in Wi-Fi " 1918281806Srpaulo "Handover Request Message"); 1919281806Srpaulo ret = -1; 1920281806Srpaulo goto out; 1921281806Srpaulo } 1922281806Srpaulo 1923281806Srpaulo wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", attr.uuid_e, WPS_UUID_LEN); 1924281806Srpaulo 1925281806Srpaulo wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password", 1926281806Srpaulo attr.oob_dev_password, attr.oob_dev_password_len); 1927281806Srpaulo dev_pw_id = WPA_GET_BE16(attr.oob_dev_password + 1928281806Srpaulo WPS_OOB_PUBKEY_HASH_LEN); 1929281806Srpaulo if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) { 1930281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID " 1931281806Srpaulo "%u in Wi-Fi Handover Request Message", dev_pw_id); 1932281806Srpaulo ret = -1; 1933281806Srpaulo goto out; 1934281806Srpaulo } 1935281806Srpaulo wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Public Key hash", 1936281806Srpaulo attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN); 1937281806Srpaulo 1938281806Srpaulo ret = wps_registrar_add_nfc_pw_token(hapd->wps->registrar, 1939281806Srpaulo attr.oob_dev_password, 1940281806Srpaulo DEV_PW_NFC_CONNECTION_HANDOVER, 1941281806Srpaulo NULL, 0, 1); 1942281806Srpaulo 1943281806Srpauloout: 1944281806Srpaulo wpabuf_free(wps); 1945281806Srpaulo return ret; 1946281806Srpaulo} 1947281806Srpaulo 1948281806Srpaulo 1949252726Srpaulostruct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef) 1950252726Srpaulo{ 1951281806Srpaulo if (hapd->conf->wps_nfc_pw_from_config) { 1952281806Srpaulo return wps_nfc_token_build(ndef, 1953281806Srpaulo hapd->conf->wps_nfc_dev_pw_id, 1954281806Srpaulo hapd->conf->wps_nfc_dh_pubkey, 1955281806Srpaulo hapd->conf->wps_nfc_dev_pw); 1956281806Srpaulo } 1957281806Srpaulo 1958252726Srpaulo return wps_nfc_token_gen(ndef, &hapd->conf->wps_nfc_dev_pw_id, 1959252726Srpaulo &hapd->conf->wps_nfc_dh_pubkey, 1960252726Srpaulo &hapd->conf->wps_nfc_dh_privkey, 1961252726Srpaulo &hapd->conf->wps_nfc_dev_pw); 1962252726Srpaulo} 1963252726Srpaulo 1964252726Srpaulo 1965252726Srpauloint hostapd_wps_nfc_token_enable(struct hostapd_data *hapd) 1966252726Srpaulo{ 1967252726Srpaulo struct wps_context *wps = hapd->wps; 1968281806Srpaulo struct wpabuf *pw; 1969252726Srpaulo 1970252726Srpaulo if (wps == NULL) 1971252726Srpaulo return -1; 1972252726Srpaulo 1973252726Srpaulo if (!hapd->conf->wps_nfc_dh_pubkey || 1974252726Srpaulo !hapd->conf->wps_nfc_dh_privkey || 1975252726Srpaulo !hapd->conf->wps_nfc_dev_pw || 1976252726Srpaulo !hapd->conf->wps_nfc_dev_pw_id) 1977252726Srpaulo return -1; 1978252726Srpaulo 1979252726Srpaulo hostapd_wps_nfc_clear(wps); 1980281806Srpaulo wpa_printf(MSG_DEBUG, 1981281806Srpaulo "WPS: Enable NFC Tag (Dev Pw Id %u) for AP interface %s (context %p)", 1982281806Srpaulo hapd->conf->wps_nfc_dev_pw_id, hapd->conf->iface, wps); 1983252726Srpaulo wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id; 1984252726Srpaulo wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey); 1985252726Srpaulo wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey); 1986281806Srpaulo pw = hapd->conf->wps_nfc_dev_pw; 1987281806Srpaulo wps->ap_nfc_dev_pw = wpabuf_alloc( 1988281806Srpaulo wpabuf_len(pw) * 2 + 1); 1989281806Srpaulo if (wps->ap_nfc_dev_pw) { 1990281806Srpaulo wpa_snprintf_hex_uppercase( 1991281806Srpaulo (char *) wpabuf_put(wps->ap_nfc_dev_pw, 1992281806Srpaulo wpabuf_len(pw) * 2), 1993281806Srpaulo wpabuf_len(pw) * 2 + 1, 1994281806Srpaulo wpabuf_head(pw), wpabuf_len(pw)); 1995281806Srpaulo } 1996252726Srpaulo 1997252726Srpaulo if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey || 1998252726Srpaulo !wps->ap_nfc_dev_pw) { 1999252726Srpaulo hostapd_wps_nfc_clear(wps); 2000252726Srpaulo return -1; 2001252726Srpaulo } 2002252726Srpaulo 2003252726Srpaulo return 0; 2004252726Srpaulo} 2005252726Srpaulo 2006252726Srpaulo 2007252726Srpaulovoid hostapd_wps_nfc_token_disable(struct hostapd_data *hapd) 2008252726Srpaulo{ 2009281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: Disable NFC token for AP interface %s", 2010281806Srpaulo hapd->conf->iface); 2011252726Srpaulo hostapd_wps_nfc_clear(hapd->wps); 2012252726Srpaulo} 2013252726Srpaulo 2014252726Srpaulo#endif /* CONFIG_WPS_NFC */ 2015