1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * Wi-Fi Protected Setup 3e5b75505Sopenharmony_ci * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi> 4e5b75505Sopenharmony_ci * 5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 6e5b75505Sopenharmony_ci * See README for more details. 7e5b75505Sopenharmony_ci */ 8e5b75505Sopenharmony_ci 9e5b75505Sopenharmony_ci#include "includes.h" 10e5b75505Sopenharmony_ci 11e5b75505Sopenharmony_ci#include "common.h" 12e5b75505Sopenharmony_ci#include "crypto/dh_group5.h" 13e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h" 14e5b75505Sopenharmony_ci#include "wps_i.h" 15e5b75505Sopenharmony_ci#include "wps_dev_attr.h" 16e5b75505Sopenharmony_ci 17e5b75505Sopenharmony_ci 18e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_TESTING 19e5b75505Sopenharmony_ciint wps_version_number = 0x20; 20e5b75505Sopenharmony_ciint wps_testing_dummy_cred = 0; 21e5b75505Sopenharmony_ciint wps_corrupt_pkhash = 0; 22e5b75505Sopenharmony_ciint wps_force_auth_types_in_use = 0; 23e5b75505Sopenharmony_ciu16 wps_force_auth_types = 0; 24e5b75505Sopenharmony_ciint wps_force_encr_types_in_use = 0; 25e5b75505Sopenharmony_ciu16 wps_force_encr_types = 0; 26e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_TESTING */ 27e5b75505Sopenharmony_ci 28e5b75505Sopenharmony_ci 29e5b75505Sopenharmony_ci/** 30e5b75505Sopenharmony_ci * wps_init - Initialize WPS Registration protocol data 31e5b75505Sopenharmony_ci * @cfg: WPS configuration 32e5b75505Sopenharmony_ci * Returns: Pointer to allocated data or %NULL on failure 33e5b75505Sopenharmony_ci * 34e5b75505Sopenharmony_ci * This function is used to initialize WPS data for a registration protocol 35e5b75505Sopenharmony_ci * instance (i.e., each run of registration protocol as a Registrar of 36e5b75505Sopenharmony_ci * Enrollee. The caller is responsible for freeing this data after the 37e5b75505Sopenharmony_ci * registration run has been completed by calling wps_deinit(). 38e5b75505Sopenharmony_ci */ 39e5b75505Sopenharmony_cistruct wps_data * wps_init(const struct wps_config *cfg) 40e5b75505Sopenharmony_ci{ 41e5b75505Sopenharmony_ci struct wps_data *data = os_zalloc(sizeof(*data)); 42e5b75505Sopenharmony_ci if (data == NULL) 43e5b75505Sopenharmony_ci return NULL; 44e5b75505Sopenharmony_ci data->wps = cfg->wps; 45e5b75505Sopenharmony_ci data->registrar = cfg->registrar; 46e5b75505Sopenharmony_ci if (cfg->registrar) { 47e5b75505Sopenharmony_ci os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN); 48e5b75505Sopenharmony_ci } else { 49e5b75505Sopenharmony_ci os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN); 50e5b75505Sopenharmony_ci os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN); 51e5b75505Sopenharmony_ci } 52e5b75505Sopenharmony_ci if (cfg->pin) { 53e5b75505Sopenharmony_ci data->dev_pw_id = cfg->dev_pw_id; 54e5b75505Sopenharmony_ci data->dev_password = os_memdup(cfg->pin, cfg->pin_len); 55e5b75505Sopenharmony_ci if (data->dev_password == NULL) { 56e5b75505Sopenharmony_ci os_free(data); 57e5b75505Sopenharmony_ci return NULL; 58e5b75505Sopenharmony_ci } 59e5b75505Sopenharmony_ci data->dev_password_len = cfg->pin_len; 60e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: AP PIN dev_password", 61e5b75505Sopenharmony_ci data->dev_password, data->dev_password_len); 62e5b75505Sopenharmony_ci } 63e5b75505Sopenharmony_ci 64e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_NFC 65e5b75505Sopenharmony_ci if (cfg->pin == NULL && 66e5b75505Sopenharmony_ci cfg->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) 67e5b75505Sopenharmony_ci data->dev_pw_id = cfg->dev_pw_id; 68e5b75505Sopenharmony_ci 69e5b75505Sopenharmony_ci if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) { 70e5b75505Sopenharmony_ci /* Keep AP PIN as alternative Device Password */ 71e5b75505Sopenharmony_ci data->alt_dev_pw_id = data->dev_pw_id; 72e5b75505Sopenharmony_ci data->alt_dev_password = data->dev_password; 73e5b75505Sopenharmony_ci data->alt_dev_password_len = data->dev_password_len; 74e5b75505Sopenharmony_ci 75e5b75505Sopenharmony_ci data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id; 76e5b75505Sopenharmony_ci data->dev_password = 77e5b75505Sopenharmony_ci os_memdup(wpabuf_head(cfg->wps->ap_nfc_dev_pw), 78e5b75505Sopenharmony_ci wpabuf_len(cfg->wps->ap_nfc_dev_pw)); 79e5b75505Sopenharmony_ci if (data->dev_password == NULL) { 80e5b75505Sopenharmony_ci os_free(data); 81e5b75505Sopenharmony_ci return NULL; 82e5b75505Sopenharmony_ci } 83e5b75505Sopenharmony_ci data->dev_password_len = wpabuf_len(cfg->wps->ap_nfc_dev_pw); 84e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: NFC dev_password", 85e5b75505Sopenharmony_ci data->dev_password, data->dev_password_len); 86e5b75505Sopenharmony_ci } 87e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_NFC */ 88e5b75505Sopenharmony_ci 89e5b75505Sopenharmony_ci data->pbc = cfg->pbc; 90e5b75505Sopenharmony_ci if (cfg->pbc) { 91e5b75505Sopenharmony_ci /* Use special PIN '00000000' for PBC */ 92e5b75505Sopenharmony_ci data->dev_pw_id = DEV_PW_PUSHBUTTON; 93e5b75505Sopenharmony_ci bin_clear_free(data->dev_password, data->dev_password_len); 94e5b75505Sopenharmony_ci data->dev_password = (u8 *) os_strdup("00000000"); 95e5b75505Sopenharmony_ci if (data->dev_password == NULL) { 96e5b75505Sopenharmony_ci os_free(data); 97e5b75505Sopenharmony_ci return NULL; 98e5b75505Sopenharmony_ci } 99e5b75505Sopenharmony_ci data->dev_password_len = 8; 100e5b75505Sopenharmony_ci } 101e5b75505Sopenharmony_ci 102e5b75505Sopenharmony_ci data->state = data->registrar ? RECV_M1 : SEND_M1; 103e5b75505Sopenharmony_ci 104e5b75505Sopenharmony_ci if (cfg->assoc_wps_ie) { 105e5b75505Sopenharmony_ci struct wps_parse_attr attr; 106e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq", 107e5b75505Sopenharmony_ci cfg->assoc_wps_ie); 108e5b75505Sopenharmony_ci if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) { 109e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE " 110e5b75505Sopenharmony_ci "from (Re)AssocReq"); 111e5b75505Sopenharmony_ci } else if (attr.request_type == NULL) { 112e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute " 113e5b75505Sopenharmony_ci "in (Re)AssocReq WPS IE"); 114e5b75505Sopenharmony_ci } else { 115e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE " 116e5b75505Sopenharmony_ci "in (Re)AssocReq WPS IE): %d", 117e5b75505Sopenharmony_ci *attr.request_type); 118e5b75505Sopenharmony_ci data->request_type = *attr.request_type; 119e5b75505Sopenharmony_ci } 120e5b75505Sopenharmony_ci } 121e5b75505Sopenharmony_ci 122e5b75505Sopenharmony_ci if (cfg->new_ap_settings) { 123e5b75505Sopenharmony_ci data->new_ap_settings = 124e5b75505Sopenharmony_ci os_memdup(cfg->new_ap_settings, 125e5b75505Sopenharmony_ci sizeof(*data->new_ap_settings)); 126e5b75505Sopenharmony_ci if (data->new_ap_settings == NULL) { 127e5b75505Sopenharmony_ci bin_clear_free(data->dev_password, 128e5b75505Sopenharmony_ci data->dev_password_len); 129e5b75505Sopenharmony_ci os_free(data); 130e5b75505Sopenharmony_ci return NULL; 131e5b75505Sopenharmony_ci } 132e5b75505Sopenharmony_ci } 133e5b75505Sopenharmony_ci 134e5b75505Sopenharmony_ci if (cfg->peer_addr) 135e5b75505Sopenharmony_ci os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN); 136e5b75505Sopenharmony_ci if (cfg->p2p_dev_addr) 137e5b75505Sopenharmony_ci os_memcpy(data->p2p_dev_addr, cfg->p2p_dev_addr, ETH_ALEN); 138e5b75505Sopenharmony_ci 139e5b75505Sopenharmony_ci data->use_psk_key = cfg->use_psk_key; 140e5b75505Sopenharmony_ci data->pbc_in_m1 = cfg->pbc_in_m1; 141e5b75505Sopenharmony_ci 142e5b75505Sopenharmony_ci if (cfg->peer_pubkey_hash) { 143e5b75505Sopenharmony_ci os_memcpy(data->peer_pubkey_hash, cfg->peer_pubkey_hash, 144e5b75505Sopenharmony_ci WPS_OOB_PUBKEY_HASH_LEN); 145e5b75505Sopenharmony_ci data->peer_pubkey_hash_set = 1; 146e5b75505Sopenharmony_ci } 147e5b75505Sopenharmony_ci 148e5b75505Sopenharmony_ci data->multi_ap_backhaul_sta = cfg->multi_ap_backhaul_sta; 149e5b75505Sopenharmony_ci 150e5b75505Sopenharmony_ci return data; 151e5b75505Sopenharmony_ci} 152e5b75505Sopenharmony_ci 153e5b75505Sopenharmony_ci 154e5b75505Sopenharmony_ci/** 155e5b75505Sopenharmony_ci * wps_deinit - Deinitialize WPS Registration protocol data 156e5b75505Sopenharmony_ci * @data: WPS Registration protocol data from wps_init() 157e5b75505Sopenharmony_ci */ 158e5b75505Sopenharmony_civoid wps_deinit(struct wps_data *data) 159e5b75505Sopenharmony_ci{ 160e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_NFC 161e5b75505Sopenharmony_ci if (data->registrar && data->nfc_pw_token) 162e5b75505Sopenharmony_ci wps_registrar_remove_nfc_pw_token(data->wps->registrar, 163e5b75505Sopenharmony_ci data->nfc_pw_token); 164e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_NFC */ 165e5b75505Sopenharmony_ci 166e5b75505Sopenharmony_ci if (data->wps_pin_revealed) { 167e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and " 168e5b75505Sopenharmony_ci "negotiation failed"); 169e5b75505Sopenharmony_ci if (data->registrar) 170e5b75505Sopenharmony_ci wps_registrar_invalidate_pin(data->wps->registrar, 171e5b75505Sopenharmony_ci data->uuid_e); 172e5b75505Sopenharmony_ci } else if (data->registrar) 173e5b75505Sopenharmony_ci wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e); 174e5b75505Sopenharmony_ci 175e5b75505Sopenharmony_ci wpabuf_clear_free(data->dh_privkey); 176e5b75505Sopenharmony_ci wpabuf_free(data->dh_pubkey_e); 177e5b75505Sopenharmony_ci wpabuf_free(data->dh_pubkey_r); 178e5b75505Sopenharmony_ci wpabuf_free(data->last_msg); 179e5b75505Sopenharmony_ci bin_clear_free(data->dev_password, data->dev_password_len); 180e5b75505Sopenharmony_ci bin_clear_free(data->alt_dev_password, data->alt_dev_password_len); 181e5b75505Sopenharmony_ci bin_clear_free(data->new_psk, data->new_psk_len); 182e5b75505Sopenharmony_ci wps_device_data_free(&data->peer_dev); 183e5b75505Sopenharmony_ci bin_clear_free(data->new_ap_settings, sizeof(*data->new_ap_settings)); 184e5b75505Sopenharmony_ci dh5_free(data->dh_ctx); 185e5b75505Sopenharmony_ci os_free(data); 186e5b75505Sopenharmony_ci} 187e5b75505Sopenharmony_ci 188e5b75505Sopenharmony_ci 189e5b75505Sopenharmony_ci/** 190e5b75505Sopenharmony_ci * wps_process_msg - Process a WPS message 191e5b75505Sopenharmony_ci * @wps: WPS Registration protocol data from wps_init() 192e5b75505Sopenharmony_ci * @op_code: Message OP Code 193e5b75505Sopenharmony_ci * @msg: Message data 194e5b75505Sopenharmony_ci * Returns: Processing result 195e5b75505Sopenharmony_ci * 196e5b75505Sopenharmony_ci * This function is used to process WPS messages with OP Codes WSC_ACK, 197e5b75505Sopenharmony_ci * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is 198e5b75505Sopenharmony_ci * responsible for reassembling the messages before calling this function. 199e5b75505Sopenharmony_ci * Response to this message is built by calling wps_get_msg(). 200e5b75505Sopenharmony_ci */ 201e5b75505Sopenharmony_cienum wps_process_res wps_process_msg(struct wps_data *wps, 202e5b75505Sopenharmony_ci enum wsc_op_code op_code, 203e5b75505Sopenharmony_ci const struct wpabuf *msg) 204e5b75505Sopenharmony_ci{ 205e5b75505Sopenharmony_ci if (wps->registrar) 206e5b75505Sopenharmony_ci return wps_registrar_process_msg(wps, op_code, msg); 207e5b75505Sopenharmony_ci else 208e5b75505Sopenharmony_ci return wps_enrollee_process_msg(wps, op_code, msg); 209e5b75505Sopenharmony_ci} 210e5b75505Sopenharmony_ci 211e5b75505Sopenharmony_ci 212e5b75505Sopenharmony_ci/** 213e5b75505Sopenharmony_ci * wps_get_msg - Build a WPS message 214e5b75505Sopenharmony_ci * @wps: WPS Registration protocol data from wps_init() 215e5b75505Sopenharmony_ci * @op_code: Buffer for returning message OP Code 216e5b75505Sopenharmony_ci * Returns: The generated WPS message or %NULL on failure 217e5b75505Sopenharmony_ci * 218e5b75505Sopenharmony_ci * This function is used to build a response to a message processed by calling 219e5b75505Sopenharmony_ci * wps_process_msg(). The caller is responsible for freeing the buffer. 220e5b75505Sopenharmony_ci */ 221e5b75505Sopenharmony_cistruct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code) 222e5b75505Sopenharmony_ci{ 223e5b75505Sopenharmony_ci if (wps->registrar) 224e5b75505Sopenharmony_ci return wps_registrar_get_msg(wps, op_code); 225e5b75505Sopenharmony_ci else 226e5b75505Sopenharmony_ci return wps_enrollee_get_msg(wps, op_code); 227e5b75505Sopenharmony_ci} 228e5b75505Sopenharmony_ci 229e5b75505Sopenharmony_ci 230e5b75505Sopenharmony_ci/** 231e5b75505Sopenharmony_ci * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC 232e5b75505Sopenharmony_ci * @msg: WPS IE contents from Beacon or Probe Response frame 233e5b75505Sopenharmony_ci * Returns: 1 if PBC Registrar is active, 0 if not 234e5b75505Sopenharmony_ci */ 235e5b75505Sopenharmony_ciint wps_is_selected_pbc_registrar(const struct wpabuf *msg) 236e5b75505Sopenharmony_ci{ 237e5b75505Sopenharmony_ci struct wps_parse_attr attr; 238e5b75505Sopenharmony_ci 239e5b75505Sopenharmony_ci /* 240e5b75505Sopenharmony_ci * In theory, this could also verify that attr.sel_reg_config_methods 241e5b75505Sopenharmony_ci * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations 242e5b75505Sopenharmony_ci * do not set Selected Registrar Config Methods attribute properly, so 243e5b75505Sopenharmony_ci * it is safer to just use Device Password ID here. 244e5b75505Sopenharmony_ci */ 245e5b75505Sopenharmony_ci 246e5b75505Sopenharmony_ci if (wps_parse_msg(msg, &attr) < 0 || 247e5b75505Sopenharmony_ci !attr.selected_registrar || *attr.selected_registrar == 0 || 248e5b75505Sopenharmony_ci !attr.dev_password_id || 249e5b75505Sopenharmony_ci WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON) 250e5b75505Sopenharmony_ci return 0; 251e5b75505Sopenharmony_ci 252e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_STRICT 253e5b75505Sopenharmony_ci if (!attr.sel_reg_config_methods || 254e5b75505Sopenharmony_ci !(WPA_GET_BE16(attr.sel_reg_config_methods) & 255e5b75505Sopenharmony_ci WPS_CONFIG_PUSHBUTTON)) 256e5b75505Sopenharmony_ci return 0; 257e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_STRICT */ 258e5b75505Sopenharmony_ci 259e5b75505Sopenharmony_ci return 1; 260e5b75505Sopenharmony_ci} 261e5b75505Sopenharmony_ci 262e5b75505Sopenharmony_ci 263e5b75505Sopenharmony_cistatic int is_selected_pin_registrar(struct wps_parse_attr *attr) 264e5b75505Sopenharmony_ci{ 265e5b75505Sopenharmony_ci /* 266e5b75505Sopenharmony_ci * In theory, this could also verify that attr.sel_reg_config_methods 267e5b75505Sopenharmony_ci * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD, 268e5b75505Sopenharmony_ci * but some deployed AP implementations do not set Selected Registrar 269e5b75505Sopenharmony_ci * Config Methods attribute properly, so it is safer to just use 270e5b75505Sopenharmony_ci * Device Password ID here. 271e5b75505Sopenharmony_ci */ 272e5b75505Sopenharmony_ci 273e5b75505Sopenharmony_ci if (!attr->selected_registrar || *attr->selected_registrar == 0) 274e5b75505Sopenharmony_ci return 0; 275e5b75505Sopenharmony_ci 276e5b75505Sopenharmony_ci if (attr->dev_password_id != NULL && 277e5b75505Sopenharmony_ci WPA_GET_BE16(attr->dev_password_id) == DEV_PW_PUSHBUTTON) 278e5b75505Sopenharmony_ci return 0; 279e5b75505Sopenharmony_ci 280e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_STRICT 281e5b75505Sopenharmony_ci if (!attr->sel_reg_config_methods || 282e5b75505Sopenharmony_ci !(WPA_GET_BE16(attr->sel_reg_config_methods) & 283e5b75505Sopenharmony_ci (WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD))) 284e5b75505Sopenharmony_ci return 0; 285e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_STRICT */ 286e5b75505Sopenharmony_ci 287e5b75505Sopenharmony_ci return 1; 288e5b75505Sopenharmony_ci} 289e5b75505Sopenharmony_ci 290e5b75505Sopenharmony_ci 291e5b75505Sopenharmony_ci/** 292e5b75505Sopenharmony_ci * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN 293e5b75505Sopenharmony_ci * @msg: WPS IE contents from Beacon or Probe Response frame 294e5b75505Sopenharmony_ci * Returns: 1 if PIN Registrar is active, 0 if not 295e5b75505Sopenharmony_ci */ 296e5b75505Sopenharmony_ciint wps_is_selected_pin_registrar(const struct wpabuf *msg) 297e5b75505Sopenharmony_ci{ 298e5b75505Sopenharmony_ci struct wps_parse_attr attr; 299e5b75505Sopenharmony_ci 300e5b75505Sopenharmony_ci if (wps_parse_msg(msg, &attr) < 0) 301e5b75505Sopenharmony_ci return 0; 302e5b75505Sopenharmony_ci 303e5b75505Sopenharmony_ci return is_selected_pin_registrar(&attr); 304e5b75505Sopenharmony_ci} 305e5b75505Sopenharmony_ci 306e5b75505Sopenharmony_ci 307e5b75505Sopenharmony_ci/** 308e5b75505Sopenharmony_ci * wps_is_addr_authorized - Check whether WPS IE authorizes MAC address 309e5b75505Sopenharmony_ci * @msg: WPS IE contents from Beacon or Probe Response frame 310e5b75505Sopenharmony_ci * @addr: MAC address to search for 311e5b75505Sopenharmony_ci * @ver1_compat: Whether to use version 1 compatibility mode 312e5b75505Sopenharmony_ci * Returns: 2 if the specified address is explicit authorized, 1 if address is 313e5b75505Sopenharmony_ci * authorized (broadcast), 0 if not 314e5b75505Sopenharmony_ci */ 315e5b75505Sopenharmony_ciint wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr, 316e5b75505Sopenharmony_ci int ver1_compat) 317e5b75505Sopenharmony_ci{ 318e5b75505Sopenharmony_ci struct wps_parse_attr attr; 319e5b75505Sopenharmony_ci unsigned int i; 320e5b75505Sopenharmony_ci const u8 *pos; 321e5b75505Sopenharmony_ci const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 322e5b75505Sopenharmony_ci 323e5b75505Sopenharmony_ci if (wps_parse_msg(msg, &attr) < 0) 324e5b75505Sopenharmony_ci return 0; 325e5b75505Sopenharmony_ci 326e5b75505Sopenharmony_ci if (!attr.version2 && ver1_compat) { 327e5b75505Sopenharmony_ci /* 328e5b75505Sopenharmony_ci * Version 1.0 AP - AuthorizedMACs not used, so revert back to 329e5b75505Sopenharmony_ci * old mechanism of using SelectedRegistrar. 330e5b75505Sopenharmony_ci */ 331e5b75505Sopenharmony_ci return is_selected_pin_registrar(&attr); 332e5b75505Sopenharmony_ci } 333e5b75505Sopenharmony_ci 334e5b75505Sopenharmony_ci if (!attr.authorized_macs) 335e5b75505Sopenharmony_ci return 0; 336e5b75505Sopenharmony_ci 337e5b75505Sopenharmony_ci pos = attr.authorized_macs; 338e5b75505Sopenharmony_ci for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) { 339e5b75505Sopenharmony_ci if (os_memcmp(pos, addr, ETH_ALEN) == 0) 340e5b75505Sopenharmony_ci return 2; 341e5b75505Sopenharmony_ci if (os_memcmp(pos, bcast, ETH_ALEN) == 0) 342e5b75505Sopenharmony_ci return 1; 343e5b75505Sopenharmony_ci pos += ETH_ALEN; 344e5b75505Sopenharmony_ci } 345e5b75505Sopenharmony_ci 346e5b75505Sopenharmony_ci return 0; 347e5b75505Sopenharmony_ci} 348e5b75505Sopenharmony_ci 349e5b75505Sopenharmony_ci 350e5b75505Sopenharmony_ci/** 351e5b75505Sopenharmony_ci * wps_ap_priority_compar - Prioritize WPS IE from two APs 352e5b75505Sopenharmony_ci * @wps_a: WPS IE contents from Beacon or Probe Response frame 353e5b75505Sopenharmony_ci * @wps_b: WPS IE contents from Beacon or Probe Response frame 354e5b75505Sopenharmony_ci * Returns: 1 if wps_b is considered more likely selection for WPS 355e5b75505Sopenharmony_ci * provisioning, -1 if wps_a is considered more like, or 0 if no preference 356e5b75505Sopenharmony_ci */ 357e5b75505Sopenharmony_ciint wps_ap_priority_compar(const struct wpabuf *wps_a, 358e5b75505Sopenharmony_ci const struct wpabuf *wps_b) 359e5b75505Sopenharmony_ci{ 360e5b75505Sopenharmony_ci struct wps_parse_attr attr; 361e5b75505Sopenharmony_ci int sel_a, sel_b; 362e5b75505Sopenharmony_ci 363e5b75505Sopenharmony_ci if (wps_a == NULL || wps_parse_msg(wps_a, &attr) < 0) 364e5b75505Sopenharmony_ci return 1; 365e5b75505Sopenharmony_ci sel_a = attr.selected_registrar && *attr.selected_registrar != 0; 366e5b75505Sopenharmony_ci 367e5b75505Sopenharmony_ci if (wps_b == NULL || wps_parse_msg(wps_b, &attr) < 0) 368e5b75505Sopenharmony_ci return -1; 369e5b75505Sopenharmony_ci sel_b = attr.selected_registrar && *attr.selected_registrar != 0; 370e5b75505Sopenharmony_ci 371e5b75505Sopenharmony_ci if (sel_a && !sel_b) 372e5b75505Sopenharmony_ci return -1; 373e5b75505Sopenharmony_ci if (!sel_a && sel_b) 374e5b75505Sopenharmony_ci return 1; 375e5b75505Sopenharmony_ci 376e5b75505Sopenharmony_ci return 0; 377e5b75505Sopenharmony_ci} 378e5b75505Sopenharmony_ci 379e5b75505Sopenharmony_ci 380e5b75505Sopenharmony_ci/** 381e5b75505Sopenharmony_ci * wps_get_uuid_e - Get UUID-E from WPS IE 382e5b75505Sopenharmony_ci * @msg: WPS IE contents from Beacon or Probe Response frame 383e5b75505Sopenharmony_ci * Returns: Pointer to UUID-E or %NULL if not included 384e5b75505Sopenharmony_ci * 385e5b75505Sopenharmony_ci * The returned pointer is to the msg contents and it remains valid only as 386e5b75505Sopenharmony_ci * long as the msg buffer is valid. 387e5b75505Sopenharmony_ci */ 388e5b75505Sopenharmony_ciconst u8 * wps_get_uuid_e(const struct wpabuf *msg) 389e5b75505Sopenharmony_ci{ 390e5b75505Sopenharmony_ci struct wps_parse_attr attr; 391e5b75505Sopenharmony_ci 392e5b75505Sopenharmony_ci if (wps_parse_msg(msg, &attr) < 0) 393e5b75505Sopenharmony_ci return NULL; 394e5b75505Sopenharmony_ci return attr.uuid_e; 395e5b75505Sopenharmony_ci} 396e5b75505Sopenharmony_ci 397e5b75505Sopenharmony_ci 398e5b75505Sopenharmony_ci/** 399e5b75505Sopenharmony_ci * wps_is_20 - Check whether WPS attributes claim support for WPS 2.0 400e5b75505Sopenharmony_ci */ 401e5b75505Sopenharmony_ciint wps_is_20(const struct wpabuf *msg) 402e5b75505Sopenharmony_ci{ 403e5b75505Sopenharmony_ci struct wps_parse_attr attr; 404e5b75505Sopenharmony_ci 405e5b75505Sopenharmony_ci if (msg == NULL || wps_parse_msg(msg, &attr) < 0) 406e5b75505Sopenharmony_ci return 0; 407e5b75505Sopenharmony_ci return attr.version2 != NULL; 408e5b75505Sopenharmony_ci} 409e5b75505Sopenharmony_ci 410e5b75505Sopenharmony_ci 411e5b75505Sopenharmony_ci/** 412e5b75505Sopenharmony_ci * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request 413e5b75505Sopenharmony_ci * @req_type: Value for Request Type attribute 414e5b75505Sopenharmony_ci * Returns: WPS IE or %NULL on failure 415e5b75505Sopenharmony_ci * 416e5b75505Sopenharmony_ci * The caller is responsible for freeing the buffer. 417e5b75505Sopenharmony_ci */ 418e5b75505Sopenharmony_cistruct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type) 419e5b75505Sopenharmony_ci{ 420e5b75505Sopenharmony_ci struct wpabuf *ie; 421e5b75505Sopenharmony_ci u8 *len; 422e5b75505Sopenharmony_ci 423e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " 424e5b75505Sopenharmony_ci "Request"); 425e5b75505Sopenharmony_ci ie = wpabuf_alloc(100); 426e5b75505Sopenharmony_ci if (ie == NULL) 427e5b75505Sopenharmony_ci return NULL; 428e5b75505Sopenharmony_ci 429e5b75505Sopenharmony_ci wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 430e5b75505Sopenharmony_ci len = wpabuf_put(ie, 1); 431e5b75505Sopenharmony_ci wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 432e5b75505Sopenharmony_ci 433e5b75505Sopenharmony_ci if (wps_build_version(ie) || 434e5b75505Sopenharmony_ci wps_build_req_type(ie, req_type) || 435e5b75505Sopenharmony_ci wps_build_wfa_ext(ie, 0, NULL, 0, 0)) { 436e5b75505Sopenharmony_ci wpabuf_free(ie); 437e5b75505Sopenharmony_ci return NULL; 438e5b75505Sopenharmony_ci } 439e5b75505Sopenharmony_ci 440e5b75505Sopenharmony_ci *len = wpabuf_len(ie) - 2; 441e5b75505Sopenharmony_ci 442e5b75505Sopenharmony_ci return ie; 443e5b75505Sopenharmony_ci} 444e5b75505Sopenharmony_ci 445e5b75505Sopenharmony_ci 446e5b75505Sopenharmony_ci/** 447e5b75505Sopenharmony_ci * wps_build_assoc_resp_ie - Build WPS IE for (Re)Association Response 448e5b75505Sopenharmony_ci * Returns: WPS IE or %NULL on failure 449e5b75505Sopenharmony_ci * 450e5b75505Sopenharmony_ci * The caller is responsible for freeing the buffer. 451e5b75505Sopenharmony_ci */ 452e5b75505Sopenharmony_cistruct wpabuf * wps_build_assoc_resp_ie(void) 453e5b75505Sopenharmony_ci{ 454e5b75505Sopenharmony_ci struct wpabuf *ie; 455e5b75505Sopenharmony_ci u8 *len; 456e5b75505Sopenharmony_ci 457e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " 458e5b75505Sopenharmony_ci "Response"); 459e5b75505Sopenharmony_ci ie = wpabuf_alloc(100); 460e5b75505Sopenharmony_ci if (ie == NULL) 461e5b75505Sopenharmony_ci return NULL; 462e5b75505Sopenharmony_ci 463e5b75505Sopenharmony_ci wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 464e5b75505Sopenharmony_ci len = wpabuf_put(ie, 1); 465e5b75505Sopenharmony_ci wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 466e5b75505Sopenharmony_ci 467e5b75505Sopenharmony_ci if (wps_build_version(ie) || 468e5b75505Sopenharmony_ci wps_build_resp_type(ie, WPS_RESP_AP) || 469e5b75505Sopenharmony_ci wps_build_wfa_ext(ie, 0, NULL, 0, 0)) { 470e5b75505Sopenharmony_ci wpabuf_free(ie); 471e5b75505Sopenharmony_ci return NULL; 472e5b75505Sopenharmony_ci } 473e5b75505Sopenharmony_ci 474e5b75505Sopenharmony_ci *len = wpabuf_len(ie) - 2; 475e5b75505Sopenharmony_ci 476e5b75505Sopenharmony_ci return ie; 477e5b75505Sopenharmony_ci} 478e5b75505Sopenharmony_ci 479e5b75505Sopenharmony_ci 480e5b75505Sopenharmony_ci/** 481e5b75505Sopenharmony_ci * wps_build_probe_req_ie - Build WPS IE for Probe Request 482e5b75505Sopenharmony_ci * @pw_id: Password ID (DEV_PW_PUSHBUTTON for active PBC and DEV_PW_DEFAULT for 483e5b75505Sopenharmony_ci * most other use cases) 484e5b75505Sopenharmony_ci * @dev: Device attributes 485e5b75505Sopenharmony_ci * @uuid: Own UUID 486e5b75505Sopenharmony_ci * @req_type: Value for Request Type attribute 487e5b75505Sopenharmony_ci * @num_req_dev_types: Number of requested device types 488e5b75505Sopenharmony_ci * @req_dev_types: Requested device types (8 * num_req_dev_types octets) or 489e5b75505Sopenharmony_ci * %NULL if none 490e5b75505Sopenharmony_ci * Returns: WPS IE or %NULL on failure 491e5b75505Sopenharmony_ci * 492e5b75505Sopenharmony_ci * The caller is responsible for freeing the buffer. 493e5b75505Sopenharmony_ci */ 494e5b75505Sopenharmony_cistruct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev, 495e5b75505Sopenharmony_ci const u8 *uuid, 496e5b75505Sopenharmony_ci enum wps_request_type req_type, 497e5b75505Sopenharmony_ci unsigned int num_req_dev_types, 498e5b75505Sopenharmony_ci const u8 *req_dev_types) 499e5b75505Sopenharmony_ci{ 500e5b75505Sopenharmony_ci struct wpabuf *ie; 501e5b75505Sopenharmony_ci 502e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request"); 503e5b75505Sopenharmony_ci 504e5b75505Sopenharmony_ci ie = wpabuf_alloc(500); 505e5b75505Sopenharmony_ci if (ie == NULL) 506e5b75505Sopenharmony_ci return NULL; 507e5b75505Sopenharmony_ci 508e5b75505Sopenharmony_ci if (wps_build_version(ie) || 509e5b75505Sopenharmony_ci wps_build_req_type(ie, req_type) || 510e5b75505Sopenharmony_ci wps_build_config_methods(ie, dev->config_methods) || 511e5b75505Sopenharmony_ci wps_build_uuid_e(ie, uuid) || 512e5b75505Sopenharmony_ci wps_build_primary_dev_type(dev, ie) || 513e5b75505Sopenharmony_ci wps_build_rf_bands(dev, ie, 0) || 514e5b75505Sopenharmony_ci wps_build_assoc_state(NULL, ie) || 515e5b75505Sopenharmony_ci wps_build_config_error(ie, WPS_CFG_NO_ERROR) || 516e5b75505Sopenharmony_ci wps_build_dev_password_id(ie, pw_id) || 517e5b75505Sopenharmony_ci wps_build_manufacturer(dev, ie) || 518e5b75505Sopenharmony_ci wps_build_model_name(dev, ie) || 519e5b75505Sopenharmony_ci wps_build_model_number(dev, ie) || 520e5b75505Sopenharmony_ci wps_build_dev_name(dev, ie) || 521e5b75505Sopenharmony_ci wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0, 0) || 522e5b75505Sopenharmony_ci wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types) 523e5b75505Sopenharmony_ci || 524e5b75505Sopenharmony_ci wps_build_secondary_dev_type(dev, ie) 525e5b75505Sopenharmony_ci ) { 526e5b75505Sopenharmony_ci wpabuf_free(ie); 527e5b75505Sopenharmony_ci return NULL; 528e5b75505Sopenharmony_ci } 529e5b75505Sopenharmony_ci 530e5b75505Sopenharmony_ci return wps_ie_encapsulate(ie); 531e5b75505Sopenharmony_ci} 532e5b75505Sopenharmony_ci 533e5b75505Sopenharmony_ci 534e5b75505Sopenharmony_civoid wps_free_pending_msgs(struct upnp_pending_message *msgs) 535e5b75505Sopenharmony_ci{ 536e5b75505Sopenharmony_ci struct upnp_pending_message *p, *prev; 537e5b75505Sopenharmony_ci p = msgs; 538e5b75505Sopenharmony_ci while (p) { 539e5b75505Sopenharmony_ci prev = p; 540e5b75505Sopenharmony_ci p = p->next; 541e5b75505Sopenharmony_ci wpabuf_free(prev->msg); 542e5b75505Sopenharmony_ci os_free(prev); 543e5b75505Sopenharmony_ci } 544e5b75505Sopenharmony_ci} 545e5b75505Sopenharmony_ci 546e5b75505Sopenharmony_ci 547e5b75505Sopenharmony_ciint wps_attr_text(struct wpabuf *data, char *buf, char *end) 548e5b75505Sopenharmony_ci{ 549e5b75505Sopenharmony_ci struct wps_parse_attr attr; 550e5b75505Sopenharmony_ci char *pos = buf; 551e5b75505Sopenharmony_ci int ret; 552e5b75505Sopenharmony_ci 553e5b75505Sopenharmony_ci if (wps_parse_msg(data, &attr) < 0) 554e5b75505Sopenharmony_ci return -1; 555e5b75505Sopenharmony_ci 556e5b75505Sopenharmony_ci if (attr.wps_state) { 557e5b75505Sopenharmony_ci if (*attr.wps_state == WPS_STATE_NOT_CONFIGURED) 558e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, 559e5b75505Sopenharmony_ci "wps_state=unconfigured\n"); 560e5b75505Sopenharmony_ci else if (*attr.wps_state == WPS_STATE_CONFIGURED) 561e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, 562e5b75505Sopenharmony_ci "wps_state=configured\n"); 563e5b75505Sopenharmony_ci else 564e5b75505Sopenharmony_ci ret = 0; 565e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 566e5b75505Sopenharmony_ci return pos - buf; 567e5b75505Sopenharmony_ci pos += ret; 568e5b75505Sopenharmony_ci } 569e5b75505Sopenharmony_ci 570e5b75505Sopenharmony_ci if (attr.ap_setup_locked && *attr.ap_setup_locked) { 571e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, 572e5b75505Sopenharmony_ci "wps_ap_setup_locked=1\n"); 573e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 574e5b75505Sopenharmony_ci return pos - buf; 575e5b75505Sopenharmony_ci pos += ret; 576e5b75505Sopenharmony_ci } 577e5b75505Sopenharmony_ci 578e5b75505Sopenharmony_ci if (attr.selected_registrar && *attr.selected_registrar) { 579e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, 580e5b75505Sopenharmony_ci "wps_selected_registrar=1\n"); 581e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 582e5b75505Sopenharmony_ci return pos - buf; 583e5b75505Sopenharmony_ci pos += ret; 584e5b75505Sopenharmony_ci } 585e5b75505Sopenharmony_ci 586e5b75505Sopenharmony_ci if (attr.dev_password_id) { 587e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, 588e5b75505Sopenharmony_ci "wps_device_password_id=%u\n", 589e5b75505Sopenharmony_ci WPA_GET_BE16(attr.dev_password_id)); 590e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 591e5b75505Sopenharmony_ci return pos - buf; 592e5b75505Sopenharmony_ci pos += ret; 593e5b75505Sopenharmony_ci } 594e5b75505Sopenharmony_ci 595e5b75505Sopenharmony_ci if (attr.sel_reg_config_methods) { 596e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, 597e5b75505Sopenharmony_ci "wps_selected_registrar_config_methods=" 598e5b75505Sopenharmony_ci "0x%04x\n", 599e5b75505Sopenharmony_ci WPA_GET_BE16(attr.sel_reg_config_methods)); 600e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 601e5b75505Sopenharmony_ci return pos - buf; 602e5b75505Sopenharmony_ci pos += ret; 603e5b75505Sopenharmony_ci } 604e5b75505Sopenharmony_ci 605e5b75505Sopenharmony_ci if (attr.primary_dev_type) { 606e5b75505Sopenharmony_ci char devtype[WPS_DEV_TYPE_BUFSIZE]; 607e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, 608e5b75505Sopenharmony_ci "wps_primary_device_type=%s\n", 609e5b75505Sopenharmony_ci wps_dev_type_bin2str(attr.primary_dev_type, 610e5b75505Sopenharmony_ci devtype, 611e5b75505Sopenharmony_ci sizeof(devtype))); 612e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 613e5b75505Sopenharmony_ci return pos - buf; 614e5b75505Sopenharmony_ci pos += ret; 615e5b75505Sopenharmony_ci } 616e5b75505Sopenharmony_ci 617e5b75505Sopenharmony_ci if (attr.dev_name) { 618e5b75505Sopenharmony_ci char *str = os_malloc(attr.dev_name_len + 1); 619e5b75505Sopenharmony_ci size_t i; 620e5b75505Sopenharmony_ci if (str == NULL) 621e5b75505Sopenharmony_ci return pos - buf; 622e5b75505Sopenharmony_ci for (i = 0; i < attr.dev_name_len; i++) { 623e5b75505Sopenharmony_ci if (attr.dev_name[i] == 0 || 624e5b75505Sopenharmony_ci is_ctrl_char(attr.dev_name[i])) 625e5b75505Sopenharmony_ci str[i] = '_'; 626e5b75505Sopenharmony_ci else 627e5b75505Sopenharmony_ci str[i] = attr.dev_name[i]; 628e5b75505Sopenharmony_ci } 629e5b75505Sopenharmony_ci str[i] = '\0'; 630e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str); 631e5b75505Sopenharmony_ci os_free(str); 632e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 633e5b75505Sopenharmony_ci return pos - buf; 634e5b75505Sopenharmony_ci pos += ret; 635e5b75505Sopenharmony_ci } 636e5b75505Sopenharmony_ci 637e5b75505Sopenharmony_ci if (attr.config_methods) { 638e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, 639e5b75505Sopenharmony_ci "wps_config_methods=0x%04x\n", 640e5b75505Sopenharmony_ci WPA_GET_BE16(attr.config_methods)); 641e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 642e5b75505Sopenharmony_ci return pos - buf; 643e5b75505Sopenharmony_ci pos += ret; 644e5b75505Sopenharmony_ci } 645e5b75505Sopenharmony_ci 646e5b75505Sopenharmony_ci return pos - buf; 647e5b75505Sopenharmony_ci} 648e5b75505Sopenharmony_ci 649e5b75505Sopenharmony_ci 650e5b75505Sopenharmony_ciconst char * wps_ei_str(enum wps_error_indication ei) 651e5b75505Sopenharmony_ci{ 652e5b75505Sopenharmony_ci switch (ei) { 653e5b75505Sopenharmony_ci case WPS_EI_NO_ERROR: 654e5b75505Sopenharmony_ci return "No Error"; 655e5b75505Sopenharmony_ci case WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED: 656e5b75505Sopenharmony_ci return "TKIP Only Prohibited"; 657e5b75505Sopenharmony_ci case WPS_EI_SECURITY_WEP_PROHIBITED: 658e5b75505Sopenharmony_ci return "WEP Prohibited"; 659e5b75505Sopenharmony_ci case WPS_EI_AUTH_FAILURE: 660e5b75505Sopenharmony_ci return "Authentication Failure"; 661e5b75505Sopenharmony_ci default: 662e5b75505Sopenharmony_ci return "Unknown"; 663e5b75505Sopenharmony_ci } 664e5b75505Sopenharmony_ci} 665