gas_serv.c revision 1846323989242844f0e857458a8939fa5836429c
104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt/* 204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * Generic advertisement service (GAS) server 31846323989242844f0e857458a8939fa5836429cDmitry Shmidt * Copyright (c) 2011-2014, Qualcomm Atheros, Inc. 404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * 504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * This software may be distributed under the terms of the BSD license. 604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * See README for more details. 704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt */ 804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "includes.h" 1004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 1104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "common.h" 1204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "common/ieee802_11_defs.h" 1304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "common/gas.h" 1404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "utils/eloop.h" 1504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "hostapd.h" 1604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "ap_config.h" 1704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "ap_drv_ops.h" 1804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "sta_info.h" 1904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "gas_serv.h" 2004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 2104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 221846323989242844f0e857458a8939fa5836429cDmitry Shmidtstatic void convert_to_protected_dual(struct wpabuf *msg) 231846323989242844f0e857458a8939fa5836429cDmitry Shmidt{ 241846323989242844f0e857458a8939fa5836429cDmitry Shmidt u8 *categ = wpabuf_mhead_u8(msg); 251846323989242844f0e857458a8939fa5836429cDmitry Shmidt *categ = WLAN_ACTION_PROTECTED_DUAL; 261846323989242844f0e857458a8939fa5836429cDmitry Shmidt} 271846323989242844f0e857458a8939fa5836429cDmitry Shmidt 281846323989242844f0e857458a8939fa5836429cDmitry Shmidt 2904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic struct gas_dialog_info * 3004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtgas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token) 3104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 3204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sta_info *sta; 3304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct gas_dialog_info *dia = NULL; 3404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int i, j; 3504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 3604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta = ap_get_sta(hapd, addr); 3704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!sta) { 3804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* 3904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * We need a STA entry to be able to maintain state for 4004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * the GAS query. 4104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt */ 4204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for " 4304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "GAS query"); 4404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta = ap_sta_add(hapd, addr); 4504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!sta) { 4604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR 4704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt " for GAS query", MAC2STR(addr)); 4804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 4904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 5004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta->flags |= WLAN_STA_GAS; 5104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* 5204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * The default inactivity is 300 seconds. We don't need 5304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * it to be that long. 5404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt */ 5504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt ap_sta_session_timeout(hapd, sta, 5); 565460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt } else { 575460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt ap_sta_replenish_timeout(hapd, sta, 5); 5804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 5904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 6004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sta->gas_dialog == NULL) { 6104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX * 6204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sizeof(struct gas_dialog_info)); 6304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sta->gas_dialog == NULL) 6404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 6504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 6604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 6704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) { 6804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (i == GAS_DIALOG_MAX) 6904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt i = 0; 7004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sta->gas_dialog[i].valid) 7104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 7204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dia = &sta->gas_dialog[i]; 7304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dia->valid = 1; 7404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dia->index = i; 7504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dia->dialog_token = dialog_token; 7604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i; 7704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return dia; 7804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 7904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 8004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_ERROR, "ANQP: Could not create dialog for " 8104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt MACSTR " dialog_token %u. Consider increasing " 8204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "GAS_DIALOG_MAX.", MAC2STR(addr), dialog_token); 8304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 8404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 8504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 8604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 8704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 8804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct gas_dialog_info * 8904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtgas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr, 9004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 dialog_token) 9104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 9204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sta_info *sta; 9304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int i; 9404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 9504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta = ap_get_sta(hapd, addr); 9604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!sta) { 9704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR, 9804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt MAC2STR(addr)); 9904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 10004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 10104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; sta->gas_dialog && i < GAS_DIALOG_MAX; i++) { 10204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sta->gas_dialog[i].dialog_token != dialog_token || 10304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt !sta->gas_dialog[i].valid) 10404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 10504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return &sta->gas_dialog[i]; 10604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 10704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for " 10804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt MACSTR " dialog_token %u", MAC2STR(addr), dialog_token); 10904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 11004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 11104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 11204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 11304949598a23f501be6eec21697465fd46a28840aDmitry Shmidtvoid gas_serv_dialog_clear(struct gas_dialog_info *dia) 11404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 11504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(dia->sd_resp); 11604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(dia, 0, sizeof(*dia)); 11704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 11804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 11904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 12004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_free_dialogs(struct hostapd_data *hapd, 12104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *sta_addr) 12204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 12304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sta_info *sta; 12404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int i; 12504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 12604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta = ap_get_sta(hapd, sta_addr); 12704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sta == NULL || sta->gas_dialog == NULL) 12804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 12904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 13004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < GAS_DIALOG_MAX; i++) { 13104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sta->gas_dialog[i].valid) 13204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 13304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 13404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 13504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(sta->gas_dialog); 13604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta->gas_dialog = NULL; 13704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 13804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 13904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 140aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20 14161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_hs_capab_list(struct hostapd_data *hapd, 14261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 14361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 14461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *len; 14561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 14661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 14761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_be24(buf, OUI_WFA); 14861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 14961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST); 15061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 0); /* Reserved */ 15161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST); 15261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_oper_friendly_name) 15361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME); 15461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_wan_metrics) 15561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS); 15661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_connection_capability) 15761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY); 15861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->nai_realm_data) 15961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY); 16061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_operating_class) 16161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS); 16261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, len); 16361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 164aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */ 16561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 16661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 16704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void anqp_add_capab_list(struct hostapd_data *hapd, 16804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *buf) 16904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 17004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 *len; 17104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 17204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST); 17304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST); 17404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hapd->conf->venue_name) 17504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_le16(buf, ANQP_VENUE_NAME); 17661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->network_auth_type) 17761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE); 17804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hapd->conf->roaming_consortium) 17904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM); 18061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->ipaddr_type_configured) 18161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY); 18261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->nai_realm_data) 18361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_NAI_REALM); 18461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->anqp_3gpp_cell_net) 18561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK); 18661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->domain_name) 18761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_DOMAIN_NAME); 188aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20 18961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_hs_capab_list(hapd, buf); 190aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */ 19104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_anqp_set_element_len(buf, len); 19204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 19304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 19404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 19504949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf) 19604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 19704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hapd->conf->venue_name) { 19804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 *len; 19904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt unsigned int i; 20004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len = gas_anqp_add_element(buf, ANQP_VENUE_NAME); 20104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_u8(buf, hapd->conf->venue_group); 20204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_u8(buf, hapd->conf->venue_type); 20304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < hapd->conf->venue_name_count; i++) { 20461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct hostapd_lang_string *vn; 20504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt vn = &hapd->conf->venue_name[i]; 20604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_u8(buf, 3 + vn->name_len); 20704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_data(buf, vn->lang, 3); 20804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_data(buf, vn->name, vn->name_len); 20904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 21004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_anqp_set_element_len(buf, len); 21104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 21204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 21304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 21404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 21561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_network_auth_type(struct hostapd_data *hapd, 21661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 21761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 21861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->network_auth_type) { 21961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE); 22061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, hapd->conf->network_auth_type_len); 22161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, hapd->conf->network_auth_type, 22261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->network_auth_type_len); 22361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 22461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 22561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 22661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 22704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void anqp_add_roaming_consortium(struct hostapd_data *hapd, 22804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *buf) 22904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 23004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt unsigned int i; 23104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 *len; 23204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 23304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM); 23404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < hapd->conf->roaming_consortium_count; i++) { 23504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_roaming_consortium *rc; 23604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt rc = &hapd->conf->roaming_consortium[i]; 23704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_u8(buf, rc->len); 23804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_data(buf, rc->oi, rc->len); 23904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 24004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_anqp_set_element_len(buf, len); 24104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 24204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 24304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 24461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd, 24561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 24661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 24761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->ipaddr_type_configured) { 24861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY); 24961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, 1); 25061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, hapd->conf->ipaddr_type_availability); 25161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 25261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 25361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 25461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 25561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_nai_realm_eap(struct wpabuf *buf, 25661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct hostapd_nai_realm_data *realm) 25761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 25861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt unsigned int i, j; 25961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 26061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, realm->eap_method_count); 26161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 26261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (i = 0; i < realm->eap_method_count; i++) { 26361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct hostapd_nai_realm_eap *eap = &realm->eap_method[i]; 26461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 2 + (3 * eap->num_auths)); 26561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, eap->eap_method); 26661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, eap->num_auths); 26761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (j = 0; j < eap->num_auths; j++) { 26861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, eap->auth_id[j]); 26961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 1); 27061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, eap->auth_val[j]); 27161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 27261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 27361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 27461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 27561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 27661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_nai_realm_data(struct wpabuf *buf, 27761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct hostapd_nai_realm_data *realm, 27861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt unsigned int realm_idx) 27961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 28061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *realm_data_len; 28161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 28261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx], 28361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt (int) os_strlen(realm->realm[realm_idx])); 28461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm_data_len = wpabuf_put(buf, 2); 28561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, realm->encoding); 28661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx])); 28761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_str(buf, realm->realm[realm_idx]); 28861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_nai_realm_eap(buf, realm); 28961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, realm_data_len); 29061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 29161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 29261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 29361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd, 29461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf, 29561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *home_realm, 29661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt size_t home_realm_len) 29761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 29861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt unsigned int i, j, k; 29961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len; 30061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct hostapd_nai_realm_data *realm; 30161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *pos, *realm_name, *end; 30261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct { 30361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt unsigned int realm_data_idx; 30461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt unsigned int realm_idx; 30561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } matches[10]; 30661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 30761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos = home_realm; 30861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt end = pos + home_realm_len; 30961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (pos + 1 > end) { 31061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query", 31161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt home_realm, home_realm_len); 31261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 31361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 31461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt num_realms = *pos++; 31561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 31661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (i = 0; i < num_realms && num_matching < 10; i++) { 31761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (pos + 2 > end) { 31861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_hexdump(MSG_DEBUG, 31961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "Truncated NAI Home Realm Query", 32061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt home_realm, home_realm_len); 32161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 32261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 32361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt encoding = *pos++; 32461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm_len = *pos++; 32561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (pos + realm_len > end) { 32661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_hexdump(MSG_DEBUG, 32761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "Truncated NAI Home Realm Query", 32861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt home_realm, home_realm_len); 32961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 33061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 33161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm_name = pos; 33261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (j = 0; j < hapd->conf->nai_realm_count && 33361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt num_matching < 10; j++) { 33461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *rpos, *rend; 33561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm = &hapd->conf->nai_realm_data[j]; 33661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (encoding != realm->encoding) 33761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt continue; 33861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 33961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rpos = realm_name; 34061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt while (rpos < realm_name + realm_len && 34161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt num_matching < 10) { 34261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (rend = rpos; 34361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rend < realm_name + realm_len; rend++) { 34461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (*rend == ';') 34561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 34661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 34761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (k = 0; k < MAX_NAI_REALMS && 34861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm->realm[k] && 34961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt num_matching < 10; k++) { 35061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if ((int) os_strlen(realm->realm[k]) != 35161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rend - rpos || 35261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_strncmp((char *) rpos, 35361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm->realm[k], 35461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rend - rpos) != 0) 35561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt continue; 35661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt matches[num_matching].realm_data_idx = 35761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt j; 35861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt matches[num_matching].realm_idx = k; 35961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt num_matching++; 36061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 36161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rpos = rend + 1; 36261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 36361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 36461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos += realm_len; 36561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 36661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 36761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM); 36861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, num_matching); 36961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 37061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* 37161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * There are two ways to format. 1. each realm in a NAI Realm Data unit 37261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * 2. all realms that share the same EAP methods in a NAI Realm Data 37361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * unit. The first format is likely to be bigger in size than the 37461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * second, but may be easier to parse and process by the receiver. 37561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt */ 37661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (i = 0; i < num_matching; i++) { 37761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d", 37861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt matches[i].realm_data_idx, matches[i].realm_idx); 37961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx]; 38061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx); 38161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 38261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, realm_list_len); 38361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return 0; 38461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 38561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 38661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 38761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf, 38861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *home_realm, size_t home_realm_len, 38961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt int nai_realm, int nai_home_realm) 39061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 39161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (nai_realm && hapd->conf->nai_realm_data) { 39261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *len; 39361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt unsigned int i, j; 39461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt len = gas_anqp_add_element(buf, ANQP_NAI_REALM); 39561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, hapd->conf->nai_realm_count); 39661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (i = 0; i < hapd->conf->nai_realm_count; i++) { 39761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *realm_data_len, *realm_len; 39861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct hostapd_nai_realm_data *realm; 39961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 40061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm = &hapd->conf->nai_realm_data[i]; 40161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm_data_len = wpabuf_put(buf, 2); 40261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, realm->encoding); 40361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm_len = wpabuf_put(buf, 1); 40461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (j = 0; realm->realm[j]; j++) { 40561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (j > 0) 40661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, ';'); 40761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_str(buf, realm->realm[j]); 40861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 40961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt *realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1; 41061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_nai_realm_eap(buf, realm); 41161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, realm_data_len); 41261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 41361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, len); 41461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else if (nai_home_realm && hapd->conf->nai_realm_data) { 41561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hs20_add_nai_home_realm_matches(hapd, buf, home_realm, 41661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt home_realm_len); 41761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 41861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 41961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 42061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 42161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd, 42261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 42361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 42461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->anqp_3gpp_cell_net) { 42561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK); 42661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, 42761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->anqp_3gpp_cell_net_len); 42861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net, 42961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->anqp_3gpp_cell_net_len); 43061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 43161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 43261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 43361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 43461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf) 43561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 43661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->domain_name) { 43761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_DOMAIN_NAME); 43861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, hapd->conf->domain_name_len); 43961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, hapd->conf->domain_name, 44061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->domain_name_len); 44161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 44261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 44361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 44461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 445aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20 446aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt 44761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_operator_friendly_name(struct hostapd_data *hapd, 44861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 44961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 45061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_oper_friendly_name) { 45161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *len; 45261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt unsigned int i; 45361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 45461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_be24(buf, OUI_WFA); 45561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 45661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME); 45761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 0); /* Reserved */ 45861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++) 45961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt { 46061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct hostapd_lang_string *vn; 46161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt vn = &hapd->conf->hs20_oper_friendly_name[i]; 46261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 3 + vn->name_len); 46361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, vn->lang, 3); 46461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, vn->name, vn->name_len); 46561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 46661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, len); 46761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 46861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 46961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 47061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 47161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_wan_metrics(struct hostapd_data *hapd, 47261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 47361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 47461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_wan_metrics) { 47561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 47661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_be24(buf, OUI_WFA); 47761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 47861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS); 47961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 0); /* Reserved */ 48061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13); 48161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, len); 48261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 48361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 48461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 48561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 48661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_connection_capability(struct hostapd_data *hapd, 48761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 48861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 48961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_connection_capability) { 49061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 49161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_be24(buf, OUI_WFA); 49261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 49361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY); 49461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 0); /* Reserved */ 49561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, hapd->conf->hs20_connection_capability, 49661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->hs20_connection_capability_len); 49761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, len); 49861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 49961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 50061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 50161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 50261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_operating_class(struct hostapd_data *hapd, 50361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 50461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 50561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_operating_class) { 50661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 50761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_be24(buf, OUI_WFA); 50861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 50961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS); 51061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 0); /* Reserved */ 51161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, hapd->conf->hs20_operating_class, 51261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->hs20_operating_class_len); 51361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, len); 51461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 51561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 51661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 517aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */ 518aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt 51961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 52004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic struct wpabuf * 52104949598a23f501be6eec21697465fd46a28840aDmitry Shmidtgas_serv_build_gas_resp_payload(struct hostapd_data *hapd, 52204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt unsigned int request, 52361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct gas_dialog_info *di, 52461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *home_realm, size_t home_realm_len) 52504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 52604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *buf; 52704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 52804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf = wpabuf_alloc(1400); 52904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (buf == NULL) 53004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 53104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 53204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (request & ANQP_REQ_CAPABILITY_LIST) 53304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt anqp_add_capab_list(hapd, buf); 53404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (request & ANQP_REQ_VENUE_NAME) 53504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt anqp_add_venue_name(hapd, buf); 53661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_NETWORK_AUTH_TYPE) 53761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_network_auth_type(hapd, buf); 53804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (request & ANQP_REQ_ROAMING_CONSORTIUM) 53904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt anqp_add_roaming_consortium(hapd, buf); 54061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY) 54161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_ip_addr_type_availability(hapd, buf); 54261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM)) 54361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len, 54461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt request & ANQP_REQ_NAI_REALM, 54561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt request & ANQP_REQ_NAI_HOME_REALM); 54661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK) 54761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_3gpp_cellular_network(hapd, buf); 54861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_DOMAIN_NAME) 54961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_domain_name(hapd, buf); 55061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 551aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20 55261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_HS_CAPABILITY_LIST) 55361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_hs_capab_list(hapd, buf); 55461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_OPERATOR_FRIENDLY_NAME) 55561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_operator_friendly_name(hapd, buf); 55661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_WAN_METRICS) 55761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_wan_metrics(hapd, buf); 55861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_CONNECTION_CAPABILITY) 55961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_connection_capability(hapd, buf); 56061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_OPERATING_CLASS) 56161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_operating_class(hapd, buf); 562aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */ 56304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 56404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return buf; 56504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 56604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 56704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 56804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx) 56904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 57004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct gas_dialog_info *dia = eloop_data; 57104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 57204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for " 57304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "dialog token %d", dia->dialog_token); 57404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 57504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_dialog_clear(dia); 57604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 57704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 57804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 57904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct anqp_query_info { 58004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt unsigned int request; 58104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt unsigned int remote_request; 58261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *home_realm_query; 58361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt size_t home_realm_query_len; 58404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u16 remote_delay; 58504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}; 58604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 58704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 58804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void set_anqp_req(unsigned int bit, const char *name, int local, 58904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt unsigned int remote, u16 remote_delay, 59004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct anqp_query_info *qi) 59104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 59204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt qi->request |= bit; 59304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (local) { 59404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name); 59504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } else if (bit & remote) { 59604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name); 59704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt qi->remote_request |= bit; 59804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (remote_delay > qi->remote_delay) 59904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt qi->remote_delay = remote_delay; 60004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } else { 60104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: %s not available", name); 60204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 60304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 60404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 60504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 60604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id, 60704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct anqp_query_info *qi) 60804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 60904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt switch (info_id) { 61004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case ANQP_CAPABILITY_LIST: 61104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0, 61204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 0, qi); 61304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 61404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case ANQP_VENUE_NAME: 61504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name", 61604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hapd->conf->venue_name != NULL, 0, 0, qi); 61704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 61861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case ANQP_NETWORK_AUTH_TYPE: 61961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type", 62061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->network_auth_type != NULL, 62161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 62261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 62304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case ANQP_ROAMING_CONSORTIUM: 62404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium", 62504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hapd->conf->roaming_consortium != NULL, 0, 0, qi); 62604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 62761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case ANQP_IP_ADDR_TYPE_AVAILABILITY: 62861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY, 62961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "IP Addr Type Availability", 63061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->ipaddr_type_configured, 63161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 63261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 63361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case ANQP_NAI_REALM: 63461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm", 63561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->nai_realm_data != NULL, 63661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 63761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 63861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case ANQP_3GPP_CELLULAR_NETWORK: 63961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK, 64061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "3GPP Cellular Network", 64161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->anqp_3gpp_cell_net != NULL, 64261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 64361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 64461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case ANQP_DOMAIN_NAME: 64561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name", 64661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->domain_name != NULL, 64761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 64861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 64904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt default: 65004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u", 65104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt info_id); 65204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 65304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 65404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 65504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 65604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 65704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void rx_anqp_query_list(struct hostapd_data *hapd, 65804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *pos, const u8 *end, 65904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct anqp_query_info *qi) 66004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 66104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list", 66204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (unsigned int) (end - pos) / 2); 66304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 66404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt while (pos + 2 <= end) { 66504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi); 66604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos += 2; 66704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 66804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 66904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 67004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 671aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20 672aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt 67361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype, 67461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct anqp_query_info *qi) 67561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 67661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt switch (subtype) { 67761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case HS20_STYPE_CAPABILITY_LIST: 67861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List", 67961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 1, 0, 0, qi); 68061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 68161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case HS20_STYPE_OPERATOR_FRIENDLY_NAME: 68261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME, 68361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "Operator Friendly Name", 68461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->hs20_oper_friendly_name != NULL, 68561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 68661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 68761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case HS20_STYPE_WAN_METRICS: 68861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics", 68961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->hs20_wan_metrics != NULL, 69061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 69161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 69261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case HS20_STYPE_CONNECTION_CAPABILITY: 69361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY, 69461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "Connection Capability", 69561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->hs20_connection_capability != NULL, 69661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 69761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 69861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case HS20_STYPE_OPERATING_CLASS: 69961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class", 70061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->hs20_operating_class != NULL, 70161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 70261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 70361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt default: 70461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u", 70561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt subtype); 70661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 70761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 70861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 70961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 71061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 71161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd, 71261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *pos, const u8 *end, 71361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct anqp_query_info *qi) 71461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 71561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt qi->request |= ANQP_REQ_NAI_HOME_REALM; 71661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt qi->home_realm_query = pos; 71761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt qi->home_realm_query_len = end - pos; 71861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->nai_realm_data != NULL) { 71961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query " 72061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "(local)"); 72161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else { 72261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not " 72361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "available"); 72461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 72561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 72661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 72761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 72861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void rx_anqp_vendor_specific(struct hostapd_data *hapd, 72961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *pos, const u8 *end, 73061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct anqp_query_info *qi) 73161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 73261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u32 oui; 73361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 subtype; 73461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 73561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (pos + 4 > end) { 73661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP " 73761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "Query element"); 73861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return; 73961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 74061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 74161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt oui = WPA_GET_BE24(pos); 74261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos += 3; 74361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (oui != OUI_WFA) { 74461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x", 74561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt oui); 74661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return; 74761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 74861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 74961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (*pos != HS20_ANQP_OUI_TYPE) { 75061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u", 75161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt *pos); 75261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return; 75361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 75461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos++; 75561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 75661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (pos + 1 >= end) 75761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return; 75861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 75961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt subtype = *pos++; 76061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos++; /* Reserved */ 76161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt switch (subtype) { 76261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case HS20_STYPE_QUERY_LIST: 76361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List"); 76461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt while (pos < end) { 76561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rx_anqp_hs_query_list(hapd, *pos, qi); 76661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos++; 76761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 76861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 76961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case HS20_STYPE_NAI_HOME_REALM_QUERY: 77061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rx_anqp_hs_nai_home_realm(hapd, pos, end, qi); 77161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 77261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt default: 77361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype " 77461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "%u", subtype); 77561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 77661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 77761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 77861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 779aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */ 780aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt 78161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 78204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_req_local_processing(struct hostapd_data *hapd, 78304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *sa, u8 dialog_token, 7841846323989242844f0e857458a8939fa5836429cDmitry Shmidt struct anqp_query_info *qi, int prot) 78504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 78604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *buf, *tx_buf; 78704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 78861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL, 78961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt qi->home_realm_query, 79061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt qi->home_realm_query_len); 79104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses", 79204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf); 79304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!buf) 79404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 79504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 79604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (wpabuf_len(buf) > hapd->gas_frag_limit || 79704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hapd->conf->gas_comeback_delay) { 79804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct gas_dialog_info *di; 79904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u16 comeback_delay = 1; 80004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 80104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hapd->conf->gas_comeback_delay) { 80204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Testing - allow overriding of the delay value */ 80304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt comeback_delay = hapd->conf->gas_comeback_delay; 80404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 80504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 80604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in " 80704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "initial response - use GAS comeback"); 80804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt di = gas_dialog_create(hapd, sa, dialog_token); 80904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!di) { 81004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_INFO, "ANQP: Could not create dialog " 81104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "for " MACSTR " (dialog token %u)", 81204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt MAC2STR(sa), dialog_token); 81304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(buf); 81404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 81504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 8161846323989242844f0e857458a8939fa5836429cDmitry Shmidt di->prot = prot; 81704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt di->sd_resp = buf; 81804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt di->sd_resp_pos = 0; 81904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tx_buf = gas_anqp_build_initial_resp_buf( 82004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token, WLAN_STATUS_SUCCESS, comeback_delay, 82104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt NULL); 82204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } else { 82304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)"); 82404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tx_buf = gas_anqp_build_initial_resp_buf( 82504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token, WLAN_STATUS_SUCCESS, 0, buf); 82604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(buf); 82704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 82804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!tx_buf) 82904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 8301846323989242844f0e857458a8939fa5836429cDmitry Shmidt if (prot) 8311846323989242844f0e857458a8939fa5836429cDmitry Shmidt convert_to_protected_dual(tx_buf); 83204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, 83304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_head(tx_buf), wpabuf_len(tx_buf)); 83404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(tx_buf); 83504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 83604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 83704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 83804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd, 83904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *sa, 8401846323989242844f0e857458a8939fa5836429cDmitry Shmidt const u8 *data, size_t len, int prot) 84104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 84204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *pos = data; 84304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *end = data + len; 84404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *next; 84504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 dialog_token; 84604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u16 slen; 84704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct anqp_query_info qi; 84804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *adv_proto; 84904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 85004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (len < 1 + 2) 85104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 85204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 85304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(&qi, 0, sizeof(qi)); 85404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 85504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token = *pos++; 85604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, 85704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "GAS: GAS Initial Request from " MACSTR " (dialog token %u) ", 85804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt MAC2STR(sa), dialog_token); 85904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 86004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (*pos != WLAN_EID_ADV_PROTO) { 86104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, 86204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "GAS: Unexpected IE in GAS Initial Request: %u", *pos); 86304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 86404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 86504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt adv_proto = pos++; 86604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 86704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt slen = *pos++; 86804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt next = pos + slen; 86904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (next > end || slen < 2) { 87004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, 87104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "GAS: Invalid IE in GAS Initial Request"); 87204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 87304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 87404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos++; /* skip QueryRespLenLimit and PAME-BI */ 87504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 87604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { 87704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *buf; 87804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, 87904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "GAS: Unsupported GAS advertisement protocol id %u", 88004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt *pos); 88104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sa[0] & 0x01) 88204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; /* Invalid source address - drop silently */ 88304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf = gas_build_initial_resp( 88404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED, 88504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 0, 2 + slen + 2); 88604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (buf == NULL) 88704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 88804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_data(buf, adv_proto, 2 + slen); 88904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_le16(buf, 0); /* Query Response Length */ 8901846323989242844f0e857458a8939fa5836429cDmitry Shmidt if (prot) 8911846323989242844f0e857458a8939fa5836429cDmitry Shmidt convert_to_protected_dual(buf); 89204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, 89304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_head(buf), wpabuf_len(buf)); 89404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(buf); 89504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 89604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 89704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 89804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos = next; 89904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Query Request */ 90004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (pos + 2 > end) 90104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 90204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt slen = WPA_GET_LE16(pos); 90304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos += 2; 90404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (pos + slen > end) 90504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 90604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt end = pos + slen; 90704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 90804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* ANQP Query Request */ 90904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt while (pos < end) { 91004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u16 info_id, elen; 91104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 91204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (pos + 4 > end) 91304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 91404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 91504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt info_id = WPA_GET_LE16(pos); 91604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos += 2; 91704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt elen = WPA_GET_LE16(pos); 91804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos += 2; 91904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 92004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (pos + elen > end) { 92104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request"); 92204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 92304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 92404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 92504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt switch (info_id) { 92604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case ANQP_QUERY_LIST: 92704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt rx_anqp_query_list(hapd, pos, pos + elen, &qi); 92804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 929aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20 93061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case ANQP_VENDOR_SPECIFIC: 93161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi); 93261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 933aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */ 93404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt default: 93504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query " 93604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Request element %u", info_id); 93704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 93804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 93904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 94004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos += elen; 94104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 94204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 9431846323989242844f0e857458a8939fa5836429cDmitry Shmidt gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot); 94404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 94504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 94604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 94704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtvoid gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst, 94804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct gas_dialog_info *dialog) 94904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 95004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *buf, *tx_buf; 95104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 dialog_token = dialog->dialog_token; 95204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t frag_len; 95304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 95404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (dialog->sd_resp == NULL) { 95504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf = gas_serv_build_gas_resp_payload(hapd, 95604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->all_requested, 95761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt dialog, NULL, 0); 95804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses", 95904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf); 96004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!buf) 96104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto tx_gas_response_done; 96204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp = buf; 96304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp_pos = 0; 96404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 96504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos; 96604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay || 96704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hapd->conf->gas_comeback_delay) { 96804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u16 comeback_delay_tus = dialog->comeback_delay + 96904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt GAS_SERV_COMEBACK_DELAY_FUDGE; 97004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u32 comeback_delay_secs, comeback_delay_usecs; 97104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 97204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hapd->conf->gas_comeback_delay) { 97304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Testing - allow overriding of the delay value */ 97404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt comeback_delay_tus = hapd->conf->gas_comeback_delay; 97504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 97604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 97704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit " 97804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "%u) and comeback delay %u, " 97904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "requesting comebacks", (unsigned int) frag_len, 98004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (unsigned int) hapd->gas_frag_limit, 98104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->comeback_delay); 98204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tx_buf = gas_anqp_build_initial_resp_buf(dialog_token, 98304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt WLAN_STATUS_SUCCESS, 98404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt comeback_delay_tus, 98504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt NULL); 98604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (tx_buf) { 98704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, 98804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "GAS: Tx GAS Initial Resp (comeback = 10TU)"); 9891846323989242844f0e857458a8939fa5836429cDmitry Shmidt if (dialog->prot) 9901846323989242844f0e857458a8939fa5836429cDmitry Shmidt convert_to_protected_dual(tx_buf); 99104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hostapd_drv_send_action(hapd, hapd->iface->freq, 0, 99204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dst, 99304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_head(tx_buf), 99404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_len(tx_buf)); 99504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 99604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(tx_buf); 99704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 99804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* start a timer of 1.5 * comeback-delay */ 99904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt comeback_delay_tus = comeback_delay_tus + 100004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (comeback_delay_tus / 2); 100104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000; 100204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt comeback_delay_usecs = (comeback_delay_tus * 1024) - 100304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (comeback_delay_secs * 1000000); 100404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt eloop_register_timeout(comeback_delay_secs, 100504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt comeback_delay_usecs, 100604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_clear_cached_ies, dialog, 100704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt NULL); 100804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto tx_gas_response_done; 100904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 101004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 101104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) + 101204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp_pos, frag_len); 101304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (buf == NULL) { 101404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation " 101504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "failed"); 101604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto tx_gas_response_done; 101704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 101804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tx_buf = gas_anqp_build_initial_resp_buf(dialog_token, 101904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt WLAN_STATUS_SUCCESS, 0, buf); 102004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(buf); 102104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (tx_buf == NULL) 102204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto tx_gas_response_done; 102304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial " 102404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Response (frag_id %d frag_len %d)", 102504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_frag_id, (int) frag_len); 102604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_frag_id++; 102704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 10281846323989242844f0e857458a8939fa5836429cDmitry Shmidt if (dialog->prot) 10291846323989242844f0e857458a8939fa5836429cDmitry Shmidt convert_to_protected_dual(tx_buf); 103004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst, 103104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_head(tx_buf), wpabuf_len(tx_buf)); 103204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(tx_buf); 103304949598a23f501be6eec21697465fd46a28840aDmitry Shmidttx_gas_response_done: 103404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_clear_cached_ies(dialog, NULL); 103504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 103604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 103704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 103804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd, 103904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *sa, 10401846323989242844f0e857458a8939fa5836429cDmitry Shmidt const u8 *data, size_t len, int prot) 104104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 104204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct gas_dialog_info *dialog; 104304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *buf, *tx_buf; 104404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 dialog_token; 104504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t frag_len; 104604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int more = 0; 104704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 104804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len); 104904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (len < 1) 105004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 105104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token = *data; 105204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u", 105304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token); 105404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 105504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog = gas_serv_dialog_find(hapd, sa, dialog_token); 105604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!dialog) { 105704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD " 105804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "response fragment for " MACSTR " dialog token %u", 105904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt MAC2STR(sa), dialog_token); 106004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 106104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sa[0] & 0x01) 106204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; /* Invalid source address - drop silently */ 106304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tx_buf = gas_anqp_build_comeback_resp_buf( 106404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0, 106504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 0, NULL); 106604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (tx_buf == NULL) 106704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 106804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto send_resp; 106904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 107004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 107104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (dialog->sd_resp == NULL) { 107204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x", 107304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->requested, dialog->received); 107404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if ((dialog->requested & dialog->received) != 107504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->requested) { 107604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Did not receive response " 107704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "from remote processing"); 107804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_dialog_clear(dialog); 107904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tx_buf = gas_anqp_build_comeback_resp_buf( 108004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token, 108104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0, 108204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt NULL); 108304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (tx_buf == NULL) 108404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 108504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto send_resp; 108604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 108704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 108804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf = gas_serv_build_gas_resp_payload(hapd, 108904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->all_requested, 109061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt dialog, NULL, 0); 109104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses", 109204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf); 109304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!buf) 109404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto rx_gas_comeback_req_done; 109504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp = buf; 109604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp_pos = 0; 109704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 109804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos; 109904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (frag_len > hapd->gas_frag_limit) { 110004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt frag_len = hapd->gas_frag_limit; 110104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt more = 1; 110204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 110304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u", 110404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (unsigned int) frag_len); 110504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) + 110604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp_pos, frag_len); 110704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (buf == NULL) { 110804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate " 110904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "buffer"); 111004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto rx_gas_comeback_req_done; 111104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 111204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token, 111304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt WLAN_STATUS_SUCCESS, 111404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_frag_id, 111504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt more, 0, buf); 111604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(buf); 111704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (tx_buf == NULL) 111804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto rx_gas_comeback_req_done; 111904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response " 112004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "(frag_id %d more=%d frag_len=%d)", 112104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_frag_id, more, (int) frag_len); 112204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_frag_id++; 112304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp_pos += frag_len; 112404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 112504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (more) { 112604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain " 112704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "to be sent", 112804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (int) (wpabuf_len(dialog->sd_resp) - 112904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp_pos)); 113004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } else { 113104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of " 113204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "SD response sent"); 113304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_dialog_clear(dialog); 113404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_free_dialogs(hapd, sa); 113504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 113604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 113704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtsend_resp: 11381846323989242844f0e857458a8939fa5836429cDmitry Shmidt if (prot) 11391846323989242844f0e857458a8939fa5836429cDmitry Shmidt convert_to_protected_dual(tx_buf); 114004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, 114104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_head(tx_buf), wpabuf_len(tx_buf)); 114204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(tx_buf); 114304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 114404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 114504949598a23f501be6eec21697465fd46a28840aDmitry Shmidtrx_gas_comeback_req_done: 114604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_clear_cached_ies(dialog, NULL); 114704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 114804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 114904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 115004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len, 115104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int freq) 115204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 115304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_data *hapd = ctx; 115404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const struct ieee80211_mgmt *mgmt; 115504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t hdr_len; 115604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *sa, *data; 11571846323989242844f0e857458a8939fa5836429cDmitry Shmidt int prot; 115804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 115904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt mgmt = (const struct ieee80211_mgmt *) buf; 116004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf; 116104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hdr_len > len) 116204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 11631846323989242844f0e857458a8939fa5836429cDmitry Shmidt if (mgmt->u.action.category != WLAN_ACTION_PUBLIC && 11641846323989242844f0e857458a8939fa5836429cDmitry Shmidt mgmt->u.action.category != WLAN_ACTION_PROTECTED_DUAL) 116504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 11661846323989242844f0e857458a8939fa5836429cDmitry Shmidt /* 11671846323989242844f0e857458a8939fa5836429cDmitry Shmidt * Note: Public Action and Protected Dual of Public Action frames share 11681846323989242844f0e857458a8939fa5836429cDmitry Shmidt * the same payload structure, so it is fine to use definitions of 11691846323989242844f0e857458a8939fa5836429cDmitry Shmidt * Public Action frames to process both. 11701846323989242844f0e857458a8939fa5836429cDmitry Shmidt */ 11711846323989242844f0e857458a8939fa5836429cDmitry Shmidt prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL; 117204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sa = mgmt->sa; 117304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len -= hdr_len; 117404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt data = &mgmt->u.action.u.public_action.action; 117504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt switch (data[0]) { 117604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case WLAN_PA_GAS_INITIAL_REQ: 11771846323989242844f0e857458a8939fa5836429cDmitry Shmidt gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot); 117804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 117904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case WLAN_PA_GAS_COMEBACK_REQ: 11801846323989242844f0e857458a8939fa5836429cDmitry Shmidt gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot); 118104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 118204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 118304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 118404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 118504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 118604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint gas_serv_init(struct hostapd_data *hapd) 118704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 11884b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt hapd->public_action_cb2 = gas_serv_rx_public_action; 11894b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt hapd->public_action_cb2_ctx = hapd; 119004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hapd->gas_frag_limit = 1400; 119104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hapd->conf->gas_frag_limit > 0) 119204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hapd->gas_frag_limit = hapd->conf->gas_frag_limit; 119304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 0; 119404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 119504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 119604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 119704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtvoid gas_serv_deinit(struct hostapd_data *hapd) 119804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 119904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 1200