1189251Ssam/* 2189251Ssam * Wi-Fi Protected Setup 3214734Srpaulo * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12214734Srpaulo#include "crypto/dh_group5.h" 13214734Srpaulo#include "common/ieee802_11_defs.h" 14189251Ssam#include "wps_i.h" 15189251Ssam#include "wps_dev_attr.h" 16189251Ssam 17189251Ssam 18252726Srpaulo#ifdef CONFIG_WPS_TESTING 19252726Srpauloint wps_version_number = 0x20; 20252726Srpauloint wps_testing_dummy_cred = 0; 21281806Srpauloint wps_corrupt_pkhash = 0; 22337817Scyint wps_force_auth_types_in_use = 0; 23337817Scyu16 wps_force_auth_types = 0; 24337817Scyint wps_force_encr_types_in_use = 0; 25337817Scyu16 wps_force_encr_types = 0; 26252726Srpaulo#endif /* CONFIG_WPS_TESTING */ 27252726Srpaulo 28252726Srpaulo 29189251Ssam/** 30189251Ssam * wps_init - Initialize WPS Registration protocol data 31189251Ssam * @cfg: WPS configuration 32189251Ssam * Returns: Pointer to allocated data or %NULL on failure 33189251Ssam * 34189251Ssam * This function is used to initialize WPS data for a registration protocol 35189251Ssam * instance (i.e., each run of registration protocol as a Registrar of 36189251Ssam * Enrollee. The caller is responsible for freeing this data after the 37189251Ssam * registration run has been completed by calling wps_deinit(). 38189251Ssam */ 39189251Ssamstruct wps_data * wps_init(const struct wps_config *cfg) 40189251Ssam{ 41189251Ssam struct wps_data *data = os_zalloc(sizeof(*data)); 42189251Ssam if (data == NULL) 43189251Ssam return NULL; 44189251Ssam data->wps = cfg->wps; 45189251Ssam data->registrar = cfg->registrar; 46189251Ssam if (cfg->registrar) { 47189251Ssam os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN); 48189251Ssam } else { 49189251Ssam os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN); 50189251Ssam os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN); 51189251Ssam } 52189251Ssam if (cfg->pin) { 53252726Srpaulo data->dev_pw_id = cfg->dev_pw_id; 54346981Scy data->dev_password = os_memdup(cfg->pin, cfg->pin_len); 55189251Ssam if (data->dev_password == NULL) { 56189251Ssam os_free(data); 57189251Ssam return NULL; 58189251Ssam } 59189251Ssam data->dev_password_len = cfg->pin_len; 60281806Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPS: AP PIN dev_password", 61281806Srpaulo data->dev_password, data->dev_password_len); 62189251Ssam } 63189251Ssam 64252726Srpaulo#ifdef CONFIG_WPS_NFC 65281806Srpaulo if (cfg->pin == NULL && 66281806Srpaulo cfg->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) 67281806Srpaulo data->dev_pw_id = cfg->dev_pw_id; 68281806Srpaulo 69252726Srpaulo if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) { 70281806Srpaulo /* Keep AP PIN as alternative Device Password */ 71281806Srpaulo data->alt_dev_pw_id = data->dev_pw_id; 72281806Srpaulo data->alt_dev_password = data->dev_password; 73281806Srpaulo data->alt_dev_password_len = data->dev_password_len; 74281806Srpaulo 75252726Srpaulo data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id; 76252726Srpaulo data->dev_password = 77346981Scy os_memdup(wpabuf_head(cfg->wps->ap_nfc_dev_pw), 78346981Scy wpabuf_len(cfg->wps->ap_nfc_dev_pw)); 79252726Srpaulo if (data->dev_password == NULL) { 80252726Srpaulo os_free(data); 81252726Srpaulo return NULL; 82252726Srpaulo } 83252726Srpaulo data->dev_password_len = wpabuf_len(cfg->wps->ap_nfc_dev_pw); 84281806Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPS: NFC dev_password", 85281806Srpaulo data->dev_password, data->dev_password_len); 86252726Srpaulo } 87252726Srpaulo#endif /* CONFIG_WPS_NFC */ 88252726Srpaulo 89189251Ssam data->pbc = cfg->pbc; 90189251Ssam if (cfg->pbc) { 91189251Ssam /* Use special PIN '00000000' for PBC */ 92189251Ssam data->dev_pw_id = DEV_PW_PUSHBUTTON; 93281806Srpaulo bin_clear_free(data->dev_password, data->dev_password_len); 94252726Srpaulo data->dev_password = (u8 *) os_strdup("00000000"); 95189251Ssam if (data->dev_password == NULL) { 96189251Ssam os_free(data); 97189251Ssam return NULL; 98189251Ssam } 99189251Ssam data->dev_password_len = 8; 100189251Ssam } 101189251Ssam 102189251Ssam data->state = data->registrar ? RECV_M1 : SEND_M1; 103189251Ssam 104189251Ssam if (cfg->assoc_wps_ie) { 105189251Ssam struct wps_parse_attr attr; 106189251Ssam wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq", 107189251Ssam cfg->assoc_wps_ie); 108189251Ssam if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) { 109189251Ssam wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE " 110189251Ssam "from (Re)AssocReq"); 111189251Ssam } else if (attr.request_type == NULL) { 112189251Ssam wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute " 113189251Ssam "in (Re)AssocReq WPS IE"); 114189251Ssam } else { 115189251Ssam wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE " 116189251Ssam "in (Re)AssocReq WPS IE): %d", 117189251Ssam *attr.request_type); 118189251Ssam data->request_type = *attr.request_type; 119189251Ssam } 120189251Ssam } 121189251Ssam 122214734Srpaulo if (cfg->new_ap_settings) { 123214734Srpaulo data->new_ap_settings = 124346981Scy os_memdup(cfg->new_ap_settings, 125346981Scy sizeof(*data->new_ap_settings)); 126214734Srpaulo if (data->new_ap_settings == NULL) { 127281806Srpaulo bin_clear_free(data->dev_password, 128281806Srpaulo data->dev_password_len); 129214734Srpaulo os_free(data); 130214734Srpaulo return NULL; 131214734Srpaulo } 132214734Srpaulo } 133214734Srpaulo 134214734Srpaulo if (cfg->peer_addr) 135214734Srpaulo os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN); 136252726Srpaulo if (cfg->p2p_dev_addr) 137252726Srpaulo os_memcpy(data->p2p_dev_addr, cfg->p2p_dev_addr, ETH_ALEN); 138214734Srpaulo 139214734Srpaulo data->use_psk_key = cfg->use_psk_key; 140252726Srpaulo data->pbc_in_m1 = cfg->pbc_in_m1; 141214734Srpaulo 142281806Srpaulo if (cfg->peer_pubkey_hash) { 143281806Srpaulo os_memcpy(data->peer_pubkey_hash, cfg->peer_pubkey_hash, 144281806Srpaulo WPS_OOB_PUBKEY_HASH_LEN); 145281806Srpaulo data->peer_pubkey_hash_set = 1; 146281806Srpaulo } 147281806Srpaulo 148346981Scy data->multi_ap_backhaul_sta = cfg->multi_ap_backhaul_sta; 149346981Scy 150189251Ssam return data; 151189251Ssam} 152189251Ssam 153189251Ssam 154189251Ssam/** 155189251Ssam * wps_deinit - Deinitialize WPS Registration protocol data 156189251Ssam * @data: WPS Registration protocol data from wps_init() 157189251Ssam */ 158189251Ssamvoid wps_deinit(struct wps_data *data) 159189251Ssam{ 160252726Srpaulo#ifdef CONFIG_WPS_NFC 161252726Srpaulo if (data->registrar && data->nfc_pw_token) 162252726Srpaulo wps_registrar_remove_nfc_pw_token(data->wps->registrar, 163252726Srpaulo data->nfc_pw_token); 164252726Srpaulo#endif /* CONFIG_WPS_NFC */ 165252726Srpaulo 166189251Ssam if (data->wps_pin_revealed) { 167189251Ssam wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and " 168189251Ssam "negotiation failed"); 169189251Ssam if (data->registrar) 170189251Ssam wps_registrar_invalidate_pin(data->wps->registrar, 171189251Ssam data->uuid_e); 172189251Ssam } else if (data->registrar) 173189251Ssam wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e); 174189251Ssam 175337817Scy wpabuf_clear_free(data->dh_privkey); 176189251Ssam wpabuf_free(data->dh_pubkey_e); 177189251Ssam wpabuf_free(data->dh_pubkey_r); 178189251Ssam wpabuf_free(data->last_msg); 179281806Srpaulo bin_clear_free(data->dev_password, data->dev_password_len); 180281806Srpaulo bin_clear_free(data->alt_dev_password, data->alt_dev_password_len); 181281806Srpaulo bin_clear_free(data->new_psk, data->new_psk_len); 182189251Ssam wps_device_data_free(&data->peer_dev); 183281806Srpaulo bin_clear_free(data->new_ap_settings, sizeof(*data->new_ap_settings)); 184214734Srpaulo dh5_free(data->dh_ctx); 185189251Ssam os_free(data); 186189251Ssam} 187189251Ssam 188189251Ssam 189189251Ssam/** 190189251Ssam * wps_process_msg - Process a WPS message 191189251Ssam * @wps: WPS Registration protocol data from wps_init() 192189251Ssam * @op_code: Message OP Code 193189251Ssam * @msg: Message data 194189251Ssam * Returns: Processing result 195189251Ssam * 196189251Ssam * This function is used to process WPS messages with OP Codes WSC_ACK, 197189251Ssam * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is 198189251Ssam * responsible for reassembling the messages before calling this function. 199189251Ssam * Response to this message is built by calling wps_get_msg(). 200189251Ssam */ 201189251Ssamenum wps_process_res wps_process_msg(struct wps_data *wps, 202189251Ssam enum wsc_op_code op_code, 203189251Ssam const struct wpabuf *msg) 204189251Ssam{ 205189251Ssam if (wps->registrar) 206189251Ssam return wps_registrar_process_msg(wps, op_code, msg); 207189251Ssam else 208189251Ssam return wps_enrollee_process_msg(wps, op_code, msg); 209189251Ssam} 210189251Ssam 211189251Ssam 212189251Ssam/** 213189251Ssam * wps_get_msg - Build a WPS message 214189251Ssam * @wps: WPS Registration protocol data from wps_init() 215189251Ssam * @op_code: Buffer for returning message OP Code 216189251Ssam * Returns: The generated WPS message or %NULL on failure 217189251Ssam * 218189251Ssam * This function is used to build a response to a message processed by calling 219189251Ssam * wps_process_msg(). The caller is responsible for freeing the buffer. 220189251Ssam */ 221189251Ssamstruct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code) 222189251Ssam{ 223189251Ssam if (wps->registrar) 224189251Ssam return wps_registrar_get_msg(wps, op_code); 225189251Ssam else 226189251Ssam return wps_enrollee_get_msg(wps, op_code); 227189251Ssam} 228189251Ssam 229189251Ssam 230189251Ssam/** 231189251Ssam * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC 232189251Ssam * @msg: WPS IE contents from Beacon or Probe Response frame 233189251Ssam * Returns: 1 if PBC Registrar is active, 0 if not 234189251Ssam */ 235189251Ssamint wps_is_selected_pbc_registrar(const struct wpabuf *msg) 236189251Ssam{ 237189251Ssam struct wps_parse_attr attr; 238189251Ssam 239189251Ssam /* 240189251Ssam * In theory, this could also verify that attr.sel_reg_config_methods 241189251Ssam * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations 242189251Ssam * do not set Selected Registrar Config Methods attribute properly, so 243189251Ssam * it is safer to just use Device Password ID here. 244189251Ssam */ 245189251Ssam 246189251Ssam if (wps_parse_msg(msg, &attr) < 0 || 247189251Ssam !attr.selected_registrar || *attr.selected_registrar == 0 || 248189251Ssam !attr.dev_password_id || 249189251Ssam WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON) 250189251Ssam return 0; 251189251Ssam 252252726Srpaulo#ifdef CONFIG_WPS_STRICT 253252726Srpaulo if (!attr.sel_reg_config_methods || 254252726Srpaulo !(WPA_GET_BE16(attr.sel_reg_config_methods) & 255252726Srpaulo WPS_CONFIG_PUSHBUTTON)) 256252726Srpaulo return 0; 257252726Srpaulo#endif /* CONFIG_WPS_STRICT */ 258252726Srpaulo 259189251Ssam return 1; 260189251Ssam} 261189251Ssam 262189251Ssam 263252726Srpaulostatic int is_selected_pin_registrar(struct wps_parse_attr *attr) 264189251Ssam{ 265189251Ssam /* 266189251Ssam * In theory, this could also verify that attr.sel_reg_config_methods 267189251Ssam * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD, 268189251Ssam * but some deployed AP implementations do not set Selected Registrar 269189251Ssam * Config Methods attribute properly, so it is safer to just use 270189251Ssam * Device Password ID here. 271189251Ssam */ 272189251Ssam 273252726Srpaulo if (!attr->selected_registrar || *attr->selected_registrar == 0) 274189251Ssam return 0; 275189251Ssam 276252726Srpaulo if (attr->dev_password_id != NULL && 277252726Srpaulo WPA_GET_BE16(attr->dev_password_id) == DEV_PW_PUSHBUTTON) 278189251Ssam return 0; 279189251Ssam 280252726Srpaulo#ifdef CONFIG_WPS_STRICT 281252726Srpaulo if (!attr->sel_reg_config_methods || 282252726Srpaulo !(WPA_GET_BE16(attr->sel_reg_config_methods) & 283252726Srpaulo (WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD))) 284189251Ssam return 0; 285252726Srpaulo#endif /* CONFIG_WPS_STRICT */ 286189251Ssam 287189251Ssam return 1; 288189251Ssam} 289189251Ssam 290189251Ssam 291189251Ssam/** 292252726Srpaulo * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN 293252726Srpaulo * @msg: WPS IE contents from Beacon or Probe Response frame 294252726Srpaulo * Returns: 1 if PIN Registrar is active, 0 if not 295252726Srpaulo */ 296252726Srpauloint wps_is_selected_pin_registrar(const struct wpabuf *msg) 297252726Srpaulo{ 298252726Srpaulo struct wps_parse_attr attr; 299252726Srpaulo 300252726Srpaulo if (wps_parse_msg(msg, &attr) < 0) 301252726Srpaulo return 0; 302252726Srpaulo 303252726Srpaulo return is_selected_pin_registrar(&attr); 304252726Srpaulo} 305252726Srpaulo 306252726Srpaulo 307252726Srpaulo/** 308252726Srpaulo * wps_is_addr_authorized - Check whether WPS IE authorizes MAC address 309252726Srpaulo * @msg: WPS IE contents from Beacon or Probe Response frame 310252726Srpaulo * @addr: MAC address to search for 311252726Srpaulo * @ver1_compat: Whether to use version 1 compatibility mode 312252726Srpaulo * Returns: 2 if the specified address is explicit authorized, 1 if address is 313252726Srpaulo * authorized (broadcast), 0 if not 314252726Srpaulo */ 315252726Srpauloint wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr, 316252726Srpaulo int ver1_compat) 317252726Srpaulo{ 318252726Srpaulo struct wps_parse_attr attr; 319252726Srpaulo unsigned int i; 320252726Srpaulo const u8 *pos; 321252726Srpaulo const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 322252726Srpaulo 323252726Srpaulo if (wps_parse_msg(msg, &attr) < 0) 324252726Srpaulo return 0; 325252726Srpaulo 326252726Srpaulo if (!attr.version2 && ver1_compat) { 327252726Srpaulo /* 328252726Srpaulo * Version 1.0 AP - AuthorizedMACs not used, so revert back to 329252726Srpaulo * old mechanism of using SelectedRegistrar. 330252726Srpaulo */ 331252726Srpaulo return is_selected_pin_registrar(&attr); 332252726Srpaulo } 333252726Srpaulo 334252726Srpaulo if (!attr.authorized_macs) 335252726Srpaulo return 0; 336252726Srpaulo 337252726Srpaulo pos = attr.authorized_macs; 338252726Srpaulo for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) { 339252726Srpaulo if (os_memcmp(pos, addr, ETH_ALEN) == 0) 340252726Srpaulo return 2; 341252726Srpaulo if (os_memcmp(pos, bcast, ETH_ALEN) == 0) 342252726Srpaulo return 1; 343252726Srpaulo pos += ETH_ALEN; 344252726Srpaulo } 345252726Srpaulo 346252726Srpaulo return 0; 347252726Srpaulo} 348252726Srpaulo 349252726Srpaulo 350252726Srpaulo/** 351252726Srpaulo * wps_ap_priority_compar - Prioritize WPS IE from two APs 352252726Srpaulo * @wps_a: WPS IE contents from Beacon or Probe Response frame 353252726Srpaulo * @wps_b: WPS IE contents from Beacon or Probe Response frame 354252726Srpaulo * Returns: 1 if wps_b is considered more likely selection for WPS 355252726Srpaulo * provisioning, -1 if wps_a is considered more like, or 0 if no preference 356252726Srpaulo */ 357252726Srpauloint wps_ap_priority_compar(const struct wpabuf *wps_a, 358252726Srpaulo const struct wpabuf *wps_b) 359252726Srpaulo{ 360289549Srpaulo struct wps_parse_attr attr; 361252726Srpaulo int sel_a, sel_b; 362252726Srpaulo 363289549Srpaulo if (wps_a == NULL || wps_parse_msg(wps_a, &attr) < 0) 364252726Srpaulo return 1; 365289549Srpaulo sel_a = attr.selected_registrar && *attr.selected_registrar != 0; 366289549Srpaulo 367289549Srpaulo if (wps_b == NULL || wps_parse_msg(wps_b, &attr) < 0) 368252726Srpaulo return -1; 369289549Srpaulo sel_b = attr.selected_registrar && *attr.selected_registrar != 0; 370252726Srpaulo 371252726Srpaulo if (sel_a && !sel_b) 372252726Srpaulo return -1; 373252726Srpaulo if (!sel_a && sel_b) 374252726Srpaulo return 1; 375252726Srpaulo 376252726Srpaulo return 0; 377252726Srpaulo} 378252726Srpaulo 379252726Srpaulo 380252726Srpaulo/** 381189251Ssam * wps_get_uuid_e - Get UUID-E from WPS IE 382189251Ssam * @msg: WPS IE contents from Beacon or Probe Response frame 383189251Ssam * Returns: Pointer to UUID-E or %NULL if not included 384189251Ssam * 385189251Ssam * The returned pointer is to the msg contents and it remains valid only as 386189251Ssam * long as the msg buffer is valid. 387189251Ssam */ 388189251Ssamconst u8 * wps_get_uuid_e(const struct wpabuf *msg) 389189251Ssam{ 390189251Ssam struct wps_parse_attr attr; 391189251Ssam 392189251Ssam if (wps_parse_msg(msg, &attr) < 0) 393189251Ssam return NULL; 394189251Ssam return attr.uuid_e; 395189251Ssam} 396189251Ssam 397189251Ssam 398189251Ssam/** 399252726Srpaulo * wps_is_20 - Check whether WPS attributes claim support for WPS 2.0 400252726Srpaulo */ 401252726Srpauloint wps_is_20(const struct wpabuf *msg) 402252726Srpaulo{ 403252726Srpaulo struct wps_parse_attr attr; 404252726Srpaulo 405252726Srpaulo if (msg == NULL || wps_parse_msg(msg, &attr) < 0) 406252726Srpaulo return 0; 407252726Srpaulo return attr.version2 != NULL; 408252726Srpaulo} 409252726Srpaulo 410252726Srpaulo 411252726Srpaulo/** 412189251Ssam * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request 413189251Ssam * @req_type: Value for Request Type attribute 414189251Ssam * Returns: WPS IE or %NULL on failure 415189251Ssam * 416189251Ssam * The caller is responsible for freeing the buffer. 417189251Ssam */ 418189251Ssamstruct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type) 419189251Ssam{ 420189251Ssam struct wpabuf *ie; 421189251Ssam u8 *len; 422189251Ssam 423189251Ssam wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " 424189251Ssam "Request"); 425189251Ssam ie = wpabuf_alloc(100); 426189251Ssam if (ie == NULL) 427189251Ssam return NULL; 428189251Ssam 429189251Ssam wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 430189251Ssam len = wpabuf_put(ie, 1); 431189251Ssam wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 432189251Ssam 433189251Ssam if (wps_build_version(ie) || 434252726Srpaulo wps_build_req_type(ie, req_type) || 435346981Scy wps_build_wfa_ext(ie, 0, NULL, 0, 0)) { 436189251Ssam wpabuf_free(ie); 437189251Ssam return NULL; 438189251Ssam } 439189251Ssam 440189251Ssam *len = wpabuf_len(ie) - 2; 441189251Ssam 442189251Ssam return ie; 443189251Ssam} 444189251Ssam 445189251Ssam 446189251Ssam/** 447214734Srpaulo * wps_build_assoc_resp_ie - Build WPS IE for (Re)Association Response 448214734Srpaulo * Returns: WPS IE or %NULL on failure 449214734Srpaulo * 450214734Srpaulo * The caller is responsible for freeing the buffer. 451214734Srpaulo */ 452214734Srpaulostruct wpabuf * wps_build_assoc_resp_ie(void) 453214734Srpaulo{ 454214734Srpaulo struct wpabuf *ie; 455214734Srpaulo u8 *len; 456214734Srpaulo 457214734Srpaulo wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " 458214734Srpaulo "Response"); 459214734Srpaulo ie = wpabuf_alloc(100); 460214734Srpaulo if (ie == NULL) 461214734Srpaulo return NULL; 462214734Srpaulo 463214734Srpaulo wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 464214734Srpaulo len = wpabuf_put(ie, 1); 465214734Srpaulo wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 466214734Srpaulo 467214734Srpaulo if (wps_build_version(ie) || 468252726Srpaulo wps_build_resp_type(ie, WPS_RESP_AP) || 469346981Scy wps_build_wfa_ext(ie, 0, NULL, 0, 0)) { 470214734Srpaulo wpabuf_free(ie); 471214734Srpaulo return NULL; 472214734Srpaulo } 473214734Srpaulo 474214734Srpaulo *len = wpabuf_len(ie) - 2; 475214734Srpaulo 476214734Srpaulo return ie; 477214734Srpaulo} 478214734Srpaulo 479214734Srpaulo 480214734Srpaulo/** 481189251Ssam * wps_build_probe_req_ie - Build WPS IE for Probe Request 482252726Srpaulo * @pw_id: Password ID (DEV_PW_PUSHBUTTON for active PBC and DEV_PW_DEFAULT for 483252726Srpaulo * most other use cases) 484189251Ssam * @dev: Device attributes 485189251Ssam * @uuid: Own UUID 486189251Ssam * @req_type: Value for Request Type attribute 487252726Srpaulo * @num_req_dev_types: Number of requested device types 488252726Srpaulo * @req_dev_types: Requested device types (8 * num_req_dev_types octets) or 489252726Srpaulo * %NULL if none 490189251Ssam * Returns: WPS IE or %NULL on failure 491189251Ssam * 492189251Ssam * The caller is responsible for freeing the buffer. 493189251Ssam */ 494252726Srpaulostruct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev, 495189251Ssam const u8 *uuid, 496252726Srpaulo enum wps_request_type req_type, 497252726Srpaulo unsigned int num_req_dev_types, 498252726Srpaulo const u8 *req_dev_types) 499189251Ssam{ 500189251Ssam struct wpabuf *ie; 501189251Ssam 502189251Ssam wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request"); 503189251Ssam 504252726Srpaulo ie = wpabuf_alloc(500); 505189251Ssam if (ie == NULL) 506189251Ssam return NULL; 507189251Ssam 508189251Ssam if (wps_build_version(ie) || 509189251Ssam wps_build_req_type(ie, req_type) || 510252726Srpaulo wps_build_config_methods(ie, dev->config_methods) || 511189251Ssam wps_build_uuid_e(ie, uuid) || 512189251Ssam wps_build_primary_dev_type(dev, ie) || 513281806Srpaulo wps_build_rf_bands(dev, ie, 0) || 514189251Ssam wps_build_assoc_state(NULL, ie) || 515189251Ssam wps_build_config_error(ie, WPS_CFG_NO_ERROR) || 516252726Srpaulo wps_build_dev_password_id(ie, pw_id) || 517252726Srpaulo wps_build_manufacturer(dev, ie) || 518252726Srpaulo wps_build_model_name(dev, ie) || 519252726Srpaulo wps_build_model_number(dev, ie) || 520252726Srpaulo wps_build_dev_name(dev, ie) || 521346981Scy wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0, 0) || 522252726Srpaulo wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types) 523252726Srpaulo || 524252726Srpaulo wps_build_secondary_dev_type(dev, ie) 525252726Srpaulo ) { 526189251Ssam wpabuf_free(ie); 527189251Ssam return NULL; 528189251Ssam } 529189251Ssam 530252726Srpaulo return wps_ie_encapsulate(ie); 531189251Ssam} 532189251Ssam 533189251Ssam 534189251Ssamvoid wps_free_pending_msgs(struct upnp_pending_message *msgs) 535189251Ssam{ 536189251Ssam struct upnp_pending_message *p, *prev; 537189251Ssam p = msgs; 538189251Ssam while (p) { 539189251Ssam prev = p; 540189251Ssam p = p->next; 541189251Ssam wpabuf_free(prev->msg); 542189251Ssam os_free(prev); 543189251Ssam } 544189251Ssam} 545214734Srpaulo 546214734Srpaulo 547214734Srpauloint wps_attr_text(struct wpabuf *data, char *buf, char *end) 548214734Srpaulo{ 549214734Srpaulo struct wps_parse_attr attr; 550214734Srpaulo char *pos = buf; 551214734Srpaulo int ret; 552214734Srpaulo 553214734Srpaulo if (wps_parse_msg(data, &attr) < 0) 554214734Srpaulo return -1; 555214734Srpaulo 556214734Srpaulo if (attr.wps_state) { 557214734Srpaulo if (*attr.wps_state == WPS_STATE_NOT_CONFIGURED) 558214734Srpaulo ret = os_snprintf(pos, end - pos, 559214734Srpaulo "wps_state=unconfigured\n"); 560214734Srpaulo else if (*attr.wps_state == WPS_STATE_CONFIGURED) 561214734Srpaulo ret = os_snprintf(pos, end - pos, 562214734Srpaulo "wps_state=configured\n"); 563214734Srpaulo else 564214734Srpaulo ret = 0; 565281806Srpaulo if (os_snprintf_error(end - pos, ret)) 566214734Srpaulo return pos - buf; 567214734Srpaulo pos += ret; 568214734Srpaulo } 569214734Srpaulo 570214734Srpaulo if (attr.ap_setup_locked && *attr.ap_setup_locked) { 571214734Srpaulo ret = os_snprintf(pos, end - pos, 572214734Srpaulo "wps_ap_setup_locked=1\n"); 573281806Srpaulo if (os_snprintf_error(end - pos, ret)) 574214734Srpaulo return pos - buf; 575214734Srpaulo pos += ret; 576214734Srpaulo } 577214734Srpaulo 578214734Srpaulo if (attr.selected_registrar && *attr.selected_registrar) { 579214734Srpaulo ret = os_snprintf(pos, end - pos, 580214734Srpaulo "wps_selected_registrar=1\n"); 581281806Srpaulo if (os_snprintf_error(end - pos, ret)) 582214734Srpaulo return pos - buf; 583214734Srpaulo pos += ret; 584214734Srpaulo } 585214734Srpaulo 586214734Srpaulo if (attr.dev_password_id) { 587214734Srpaulo ret = os_snprintf(pos, end - pos, 588214734Srpaulo "wps_device_password_id=%u\n", 589214734Srpaulo WPA_GET_BE16(attr.dev_password_id)); 590281806Srpaulo if (os_snprintf_error(end - pos, ret)) 591214734Srpaulo return pos - buf; 592214734Srpaulo pos += ret; 593214734Srpaulo } 594214734Srpaulo 595214734Srpaulo if (attr.sel_reg_config_methods) { 596214734Srpaulo ret = os_snprintf(pos, end - pos, 597214734Srpaulo "wps_selected_registrar_config_methods=" 598214734Srpaulo "0x%04x\n", 599214734Srpaulo WPA_GET_BE16(attr.sel_reg_config_methods)); 600281806Srpaulo if (os_snprintf_error(end - pos, ret)) 601214734Srpaulo return pos - buf; 602214734Srpaulo pos += ret; 603214734Srpaulo } 604214734Srpaulo 605214734Srpaulo if (attr.primary_dev_type) { 606214734Srpaulo char devtype[WPS_DEV_TYPE_BUFSIZE]; 607214734Srpaulo ret = os_snprintf(pos, end - pos, 608214734Srpaulo "wps_primary_device_type=%s\n", 609214734Srpaulo wps_dev_type_bin2str(attr.primary_dev_type, 610214734Srpaulo devtype, 611214734Srpaulo sizeof(devtype))); 612281806Srpaulo if (os_snprintf_error(end - pos, ret)) 613214734Srpaulo return pos - buf; 614214734Srpaulo pos += ret; 615214734Srpaulo } 616214734Srpaulo 617214734Srpaulo if (attr.dev_name) { 618214734Srpaulo char *str = os_malloc(attr.dev_name_len + 1); 619214734Srpaulo size_t i; 620214734Srpaulo if (str == NULL) 621214734Srpaulo return pos - buf; 622214734Srpaulo for (i = 0; i < attr.dev_name_len; i++) { 623289549Srpaulo if (attr.dev_name[i] == 0 || 624289549Srpaulo is_ctrl_char(attr.dev_name[i])) 625214734Srpaulo str[i] = '_'; 626214734Srpaulo else 627214734Srpaulo str[i] = attr.dev_name[i]; 628214734Srpaulo } 629214734Srpaulo str[i] = '\0'; 630214734Srpaulo ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str); 631214734Srpaulo os_free(str); 632281806Srpaulo if (os_snprintf_error(end - pos, ret)) 633214734Srpaulo return pos - buf; 634214734Srpaulo pos += ret; 635214734Srpaulo } 636214734Srpaulo 637214734Srpaulo if (attr.config_methods) { 638214734Srpaulo ret = os_snprintf(pos, end - pos, 639214734Srpaulo "wps_config_methods=0x%04x\n", 640214734Srpaulo WPA_GET_BE16(attr.config_methods)); 641281806Srpaulo if (os_snprintf_error(end - pos, ret)) 642214734Srpaulo return pos - buf; 643214734Srpaulo pos += ret; 644214734Srpaulo } 645214734Srpaulo 646214734Srpaulo return pos - buf; 647214734Srpaulo} 648281806Srpaulo 649281806Srpaulo 650281806Srpauloconst char * wps_ei_str(enum wps_error_indication ei) 651281806Srpaulo{ 652281806Srpaulo switch (ei) { 653281806Srpaulo case WPS_EI_NO_ERROR: 654281806Srpaulo return "No Error"; 655281806Srpaulo case WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED: 656281806Srpaulo return "TKIP Only Prohibited"; 657281806Srpaulo case WPS_EI_SECURITY_WEP_PROHIBITED: 658281806Srpaulo return "WEP Prohibited"; 659281806Srpaulo case WPS_EI_AUTH_FAILURE: 660281806Srpaulo return "Authentication Failure"; 661281806Srpaulo default: 662281806Srpaulo return "Unknown"; 663281806Srpaulo } 664281806Srpaulo} 665