104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt/* 204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * Generic advertisement service (GAS) server 304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * Copyright (c) 2011-2012, 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 2204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic struct gas_dialog_info * 2304949598a23f501be6eec21697465fd46a28840aDmitry Shmidtgas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token) 2404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 2504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sta_info *sta; 2604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct gas_dialog_info *dia = NULL; 2704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int i, j; 2804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 2904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta = ap_get_sta(hapd, addr); 3004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!sta) { 3104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* 3204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * We need a STA entry to be able to maintain state for 3304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * the GAS query. 3404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt */ 3504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for " 3604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "GAS query"); 3704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta = ap_sta_add(hapd, addr); 3804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!sta) { 3904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR 4004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt " for GAS query", MAC2STR(addr)); 4104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 4204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 4304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta->flags |= WLAN_STA_GAS; 4404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* 4504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * The default inactivity is 300 seconds. We don't need 4604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * it to be that long. 4704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt */ 4804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt ap_sta_session_timeout(hapd, sta, 5); 4904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 5004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 5104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sta->gas_dialog == NULL) { 5204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX * 5304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sizeof(struct gas_dialog_info)); 5404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sta->gas_dialog == NULL) 5504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 5604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 5704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 5804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) { 5904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (i == GAS_DIALOG_MAX) 6004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt i = 0; 6104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sta->gas_dialog[i].valid) 6204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 6304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dia = &sta->gas_dialog[i]; 6404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dia->valid = 1; 6504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dia->index = i; 6604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dia->dialog_token = dialog_token; 6704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i; 6804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return dia; 6904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 7004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 7104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_ERROR, "ANQP: Could not create dialog for " 7204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt MACSTR " dialog_token %u. Consider increasing " 7304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "GAS_DIALOG_MAX.", MAC2STR(addr), dialog_token); 7404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 7504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 7604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 7704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 7804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 7904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct gas_dialog_info * 8004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtgas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr, 8104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 dialog_token) 8204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 8304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sta_info *sta; 8404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int i; 8504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 8604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta = ap_get_sta(hapd, addr); 8704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!sta) { 8804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR, 8904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt MAC2STR(addr)); 9004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 9104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 9204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; sta->gas_dialog && i < GAS_DIALOG_MAX; i++) { 9304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sta->gas_dialog[i].dialog_token != dialog_token || 9404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt !sta->gas_dialog[i].valid) 9504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 9604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return &sta->gas_dialog[i]; 9704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 9804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for " 9904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt MACSTR " dialog_token %u", MAC2STR(addr), dialog_token); 10004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 10104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 10204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 10304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 10404949598a23f501be6eec21697465fd46a28840aDmitry Shmidtvoid gas_serv_dialog_clear(struct gas_dialog_info *dia) 10504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 10604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(dia->sd_resp); 10704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(dia, 0, sizeof(*dia)); 10804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 10904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 11004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 11104949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_free_dialogs(struct hostapd_data *hapd, 11204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *sta_addr) 11304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 11404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sta_info *sta; 11504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int i; 11604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 11704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta = ap_get_sta(hapd, sta_addr); 11804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sta == NULL || sta->gas_dialog == NULL) 11904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 12004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 12104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < GAS_DIALOG_MAX; i++) { 12204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sta->gas_dialog[i].valid) 12304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 12404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 12504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 12604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(sta->gas_dialog); 12704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sta->gas_dialog = NULL; 12804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 12904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 13004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 131aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20 13261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_hs_capab_list(struct hostapd_data *hapd, 13361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 13461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 13561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *len; 13661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 13861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_be24(buf, OUI_WFA); 13961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 14061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST); 14161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 0); /* Reserved */ 14261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST); 14361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_oper_friendly_name) 14461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME); 14561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_wan_metrics) 14661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS); 14761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_connection_capability) 14861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY); 14961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->nai_realm_data) 15061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY); 15161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_operating_class) 15261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS); 15361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, len); 15461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 155aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */ 15661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 15761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 15804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void anqp_add_capab_list(struct hostapd_data *hapd, 15904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *buf) 16004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 16104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 *len; 16204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 16304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST); 16404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST); 16504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hapd->conf->venue_name) 16604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_le16(buf, ANQP_VENUE_NAME); 16761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->network_auth_type) 16861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE); 16904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hapd->conf->roaming_consortium) 17004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM); 17161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->ipaddr_type_configured) 17261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY); 17361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->nai_realm_data) 17461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_NAI_REALM); 17561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->anqp_3gpp_cell_net) 17661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK); 17761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->domain_name) 17861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_DOMAIN_NAME); 179aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20 18061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_hs_capab_list(hapd, buf); 181aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */ 18204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_anqp_set_element_len(buf, len); 18304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 18404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 18504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 18604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf) 18704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 18804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hapd->conf->venue_name) { 18904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 *len; 19004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt unsigned int i; 19104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len = gas_anqp_add_element(buf, ANQP_VENUE_NAME); 19204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_u8(buf, hapd->conf->venue_group); 19304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_u8(buf, hapd->conf->venue_type); 19404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < hapd->conf->venue_name_count; i++) { 19561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct hostapd_lang_string *vn; 19604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt vn = &hapd->conf->venue_name[i]; 19704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_u8(buf, 3 + vn->name_len); 19804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_data(buf, vn->lang, 3); 19904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_data(buf, vn->name, vn->name_len); 20004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 20104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_anqp_set_element_len(buf, len); 20204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 20304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 20404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 20504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 20661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_network_auth_type(struct hostapd_data *hapd, 20761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 20861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 20961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->network_auth_type) { 21061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE); 21161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, hapd->conf->network_auth_type_len); 21261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, hapd->conf->network_auth_type, 21361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->network_auth_type_len); 21461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 21561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 21661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 21761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 21804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void anqp_add_roaming_consortium(struct hostapd_data *hapd, 21904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *buf) 22004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 22104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt unsigned int i; 22204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 *len; 22304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 22404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM); 22504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < hapd->conf->roaming_consortium_count; i++) { 22604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_roaming_consortium *rc; 22704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt rc = &hapd->conf->roaming_consortium[i]; 22804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_u8(buf, rc->len); 22904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_data(buf, rc->oi, rc->len); 23004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 23104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_anqp_set_element_len(buf, len); 23204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 23304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 23404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 23561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd, 23661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 23761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 23861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->ipaddr_type_configured) { 23961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY); 24061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, 1); 24161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, hapd->conf->ipaddr_type_availability); 24261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 24361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 24461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 24561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 24661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_nai_realm_eap(struct wpabuf *buf, 24761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct hostapd_nai_realm_data *realm) 24861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 24961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt unsigned int i, j; 25061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 25161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, realm->eap_method_count); 25261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 25361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (i = 0; i < realm->eap_method_count; i++) { 25461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct hostapd_nai_realm_eap *eap = &realm->eap_method[i]; 25561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 2 + (3 * eap->num_auths)); 25661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, eap->eap_method); 25761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, eap->num_auths); 25861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (j = 0; j < eap->num_auths; j++) { 25961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, eap->auth_id[j]); 26061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 1); 26161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, eap->auth_val[j]); 26261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 26361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 26461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 26561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 26661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 26761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_nai_realm_data(struct wpabuf *buf, 26861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct hostapd_nai_realm_data *realm, 26961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt unsigned int realm_idx) 27061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 27161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *realm_data_len; 27261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 27361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx], 27461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt (int) os_strlen(realm->realm[realm_idx])); 27561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm_data_len = wpabuf_put(buf, 2); 27661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, realm->encoding); 27761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx])); 27861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_str(buf, realm->realm[realm_idx]); 27961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_nai_realm_eap(buf, realm); 28061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, realm_data_len); 28161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 28261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 28361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 28461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd, 28561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf, 28661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *home_realm, 28761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt size_t home_realm_len) 28861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 28961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt unsigned int i, j, k; 29061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len; 29161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct hostapd_nai_realm_data *realm; 29261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *pos, *realm_name, *end; 29361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct { 29461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt unsigned int realm_data_idx; 29561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt unsigned int realm_idx; 29661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } matches[10]; 29761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 29861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos = home_realm; 29961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt end = pos + home_realm_len; 30061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (pos + 1 > end) { 30161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query", 30261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt home_realm, home_realm_len); 30361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 30461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 30561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt num_realms = *pos++; 30661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 30761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (i = 0; i < num_realms && num_matching < 10; i++) { 30861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (pos + 2 > end) { 30961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_hexdump(MSG_DEBUG, 31061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "Truncated NAI Home Realm Query", 31161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt home_realm, home_realm_len); 31261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 31361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 31461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt encoding = *pos++; 31561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm_len = *pos++; 31661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (pos + realm_len > end) { 31761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_hexdump(MSG_DEBUG, 31861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "Truncated NAI Home Realm Query", 31961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt home_realm, home_realm_len); 32061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 32161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 32261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm_name = pos; 32361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (j = 0; j < hapd->conf->nai_realm_count && 32461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt num_matching < 10; j++) { 32561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *rpos, *rend; 32661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm = &hapd->conf->nai_realm_data[j]; 32761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (encoding != realm->encoding) 32861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt continue; 32961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 33061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rpos = realm_name; 33161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt while (rpos < realm_name + realm_len && 33261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt num_matching < 10) { 33361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (rend = rpos; 33461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rend < realm_name + realm_len; rend++) { 33561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (*rend == ';') 33661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 33761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 33861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (k = 0; k < MAX_NAI_REALMS && 33961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm->realm[k] && 34061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt num_matching < 10; k++) { 34161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if ((int) os_strlen(realm->realm[k]) != 34261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rend - rpos || 34361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_strncmp((char *) rpos, 34461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm->realm[k], 34561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rend - rpos) != 0) 34661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt continue; 34761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt matches[num_matching].realm_data_idx = 34861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt j; 34961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt matches[num_matching].realm_idx = k; 35061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt num_matching++; 35161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 35261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rpos = rend + 1; 35361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 35461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 35561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos += realm_len; 35661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 35761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 35861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM); 35961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, num_matching); 36061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 36161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* 36261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * There are two ways to format. 1. each realm in a NAI Realm Data unit 36361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * 2. all realms that share the same EAP methods in a NAI Realm Data 36461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * unit. The first format is likely to be bigger in size than the 36561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * second, but may be easier to parse and process by the receiver. 36661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt */ 36761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (i = 0; i < num_matching; i++) { 36861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d", 36961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt matches[i].realm_data_idx, matches[i].realm_idx); 37061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx]; 37161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx); 37261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 37361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, realm_list_len); 37461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return 0; 37561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 37661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 37761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 37861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf, 37961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *home_realm, size_t home_realm_len, 38061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt int nai_realm, int nai_home_realm) 38161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 38261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (nai_realm && hapd->conf->nai_realm_data) { 38361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *len; 38461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt unsigned int i, j; 38561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt len = gas_anqp_add_element(buf, ANQP_NAI_REALM); 38661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, hapd->conf->nai_realm_count); 38761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (i = 0; i < hapd->conf->nai_realm_count; i++) { 38861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *realm_data_len, *realm_len; 38961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct hostapd_nai_realm_data *realm; 39061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 39161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm = &hapd->conf->nai_realm_data[i]; 39261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm_data_len = wpabuf_put(buf, 2); 39361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, realm->encoding); 39461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt realm_len = wpabuf_put(buf, 1); 39561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (j = 0; realm->realm[j]; j++) { 39661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (j > 0) 39761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, ';'); 39861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_str(buf, realm->realm[j]); 39961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 40061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt *realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1; 40161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_nai_realm_eap(buf, realm); 40261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, realm_data_len); 40361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 40461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, len); 40561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else if (nai_home_realm && hapd->conf->nai_realm_data) { 40661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hs20_add_nai_home_realm_matches(hapd, buf, home_realm, 40761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt home_realm_len); 40861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 40961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 41061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 41161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 41261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd, 41361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 41461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 41561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->anqp_3gpp_cell_net) { 41661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK); 41761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, 41861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->anqp_3gpp_cell_net_len); 41961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net, 42061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->anqp_3gpp_cell_net_len); 42161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 42261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 42361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 42461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 42561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf) 42661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 42761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->domain_name) { 42861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, ANQP_DOMAIN_NAME); 42961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_le16(buf, hapd->conf->domain_name_len); 43061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, hapd->conf->domain_name, 43161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->domain_name_len); 43261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 43361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 43461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 43561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 436aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20 437aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt 43861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_operator_friendly_name(struct hostapd_data *hapd, 43961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 44061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 44161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_oper_friendly_name) { 44261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *len; 44361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt unsigned int i; 44461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 44561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_be24(buf, OUI_WFA); 44661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 44761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME); 44861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 0); /* Reserved */ 44961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++) 45061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt { 45161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct hostapd_lang_string *vn; 45261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt vn = &hapd->conf->hs20_oper_friendly_name[i]; 45361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 3 + vn->name_len); 45461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, vn->lang, 3); 45561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, vn->name, vn->name_len); 45661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 45761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, len); 45861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 45961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 46061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 46161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 46261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_wan_metrics(struct hostapd_data *hapd, 46361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 46461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 46561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_wan_metrics) { 46661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 46761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_be24(buf, OUI_WFA); 46861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 46961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS); 47061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 0); /* Reserved */ 47161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13); 47261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, len); 47361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 47461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 47561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 47661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 47761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_connection_capability(struct hostapd_data *hapd, 47861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 47961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 48061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_connection_capability) { 48161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 48261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_be24(buf, OUI_WFA); 48361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 48461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY); 48561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 0); /* Reserved */ 48661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, hapd->conf->hs20_connection_capability, 48761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->hs20_connection_capability_len); 48861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, len); 48961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 49061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 49161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 49261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 49361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_operating_class(struct hostapd_data *hapd, 49461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *buf) 49561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 49661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->hs20_operating_class) { 49761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 49861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_be24(buf, OUI_WFA); 49961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 50061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS); 50161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 0); /* Reserved */ 50261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, hapd->conf->hs20_operating_class, 50361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->hs20_operating_class_len); 50461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt gas_anqp_set_element_len(buf, len); 50561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 50661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 50761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 508aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */ 509aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt 51061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 51104949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic struct wpabuf * 51204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtgas_serv_build_gas_resp_payload(struct hostapd_data *hapd, 51304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt unsigned int request, 51461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct gas_dialog_info *di, 51561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *home_realm, size_t home_realm_len) 51604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 51704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *buf; 51804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 51904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf = wpabuf_alloc(1400); 52004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (buf == NULL) 52104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 52204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 52304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (request & ANQP_REQ_CAPABILITY_LIST) 52404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt anqp_add_capab_list(hapd, buf); 52504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (request & ANQP_REQ_VENUE_NAME) 52604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt anqp_add_venue_name(hapd, buf); 52761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_NETWORK_AUTH_TYPE) 52861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_network_auth_type(hapd, buf); 52904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (request & ANQP_REQ_ROAMING_CONSORTIUM) 53004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt anqp_add_roaming_consortium(hapd, buf); 53161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY) 53261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_ip_addr_type_availability(hapd, buf); 53361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM)) 53461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len, 53561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt request & ANQP_REQ_NAI_REALM, 53661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt request & ANQP_REQ_NAI_HOME_REALM); 53761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK) 53861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_3gpp_cellular_network(hapd, buf); 53961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_DOMAIN_NAME) 54061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_domain_name(hapd, buf); 54161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 542aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20 54361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_HS_CAPABILITY_LIST) 54461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_hs_capab_list(hapd, buf); 54561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_OPERATOR_FRIENDLY_NAME) 54661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_operator_friendly_name(hapd, buf); 54761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_WAN_METRICS) 54861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_wan_metrics(hapd, buf); 54961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_CONNECTION_CAPABILITY) 55061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_connection_capability(hapd, buf); 55161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (request & ANQP_REQ_OPERATING_CLASS) 55261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt anqp_add_operating_class(hapd, buf); 553aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */ 55404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 55504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return buf; 55604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 55704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 55804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 55904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx) 56004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 56104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct gas_dialog_info *dia = eloop_data; 56204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 56304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for " 56404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "dialog token %d", dia->dialog_token); 56504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 56604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_dialog_clear(dia); 56704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 56804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 56904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 57004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct anqp_query_info { 57104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt unsigned int request; 57204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt unsigned int remote_request; 57361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *home_realm_query; 57461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt size_t home_realm_query_len; 57504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u16 remote_delay; 57604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}; 57704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 57804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 57904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void set_anqp_req(unsigned int bit, const char *name, int local, 58004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt unsigned int remote, u16 remote_delay, 58104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct anqp_query_info *qi) 58204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 58304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt qi->request |= bit; 58404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (local) { 58504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name); 58604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } else if (bit & remote) { 58704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name); 58804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt qi->remote_request |= bit; 58904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (remote_delay > qi->remote_delay) 59004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt qi->remote_delay = remote_delay; 59104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } else { 59204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: %s not available", name); 59304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 59404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 59504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 59604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 59704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id, 59804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct anqp_query_info *qi) 59904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 60004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt switch (info_id) { 60104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case ANQP_CAPABILITY_LIST: 60204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0, 60304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 0, qi); 60404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 60504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case ANQP_VENUE_NAME: 60604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name", 60704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hapd->conf->venue_name != NULL, 0, 0, qi); 60804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 60961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case ANQP_NETWORK_AUTH_TYPE: 61061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type", 61161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->network_auth_type != NULL, 61261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 61361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 61404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case ANQP_ROAMING_CONSORTIUM: 61504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium", 61604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hapd->conf->roaming_consortium != NULL, 0, 0, qi); 61704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 61861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case ANQP_IP_ADDR_TYPE_AVAILABILITY: 61961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY, 62061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "IP Addr Type Availability", 62161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->ipaddr_type_configured, 62261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 62361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 62461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case ANQP_NAI_REALM: 62561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm", 62661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->nai_realm_data != NULL, 62761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 62861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 62961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case ANQP_3GPP_CELLULAR_NETWORK: 63061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK, 63161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "3GPP Cellular Network", 63261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->anqp_3gpp_cell_net != NULL, 63361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 63461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 63561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case ANQP_DOMAIN_NAME: 63661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name", 63761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->domain_name != NULL, 63861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 63961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 64004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt default: 64104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u", 64204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt info_id); 64304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 64404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 64504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 64604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 64704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 64804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void rx_anqp_query_list(struct hostapd_data *hapd, 64904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *pos, const u8 *end, 65004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct anqp_query_info *qi) 65104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 65204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list", 65304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (unsigned int) (end - pos) / 2); 65404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 65504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt while (pos + 2 <= end) { 65604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi); 65704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos += 2; 65804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 65904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 66004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 66104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 662aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20 663aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt 66461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype, 66561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct anqp_query_info *qi) 66661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 66761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt switch (subtype) { 66861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case HS20_STYPE_CAPABILITY_LIST: 66961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List", 67061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 1, 0, 0, qi); 67161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 67261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case HS20_STYPE_OPERATOR_FRIENDLY_NAME: 67361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME, 67461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "Operator Friendly Name", 67561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->hs20_oper_friendly_name != NULL, 67661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 67761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 67861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case HS20_STYPE_WAN_METRICS: 67961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics", 68061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->hs20_wan_metrics != NULL, 68161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 68261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 68361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case HS20_STYPE_CONNECTION_CAPABILITY: 68461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY, 68561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "Connection Capability", 68661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->hs20_connection_capability != NULL, 68761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 68861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 68961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case HS20_STYPE_OPERATING_CLASS: 69061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class", 69161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt hapd->conf->hs20_operating_class != NULL, 69261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 0, 0, qi); 69361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 69461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt default: 69561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u", 69661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt subtype); 69761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 69861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 69961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 70061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 70161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 70261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd, 70361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *pos, const u8 *end, 70461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct anqp_query_info *qi) 70561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 70661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt qi->request |= ANQP_REQ_NAI_HOME_REALM; 70761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt qi->home_realm_query = pos; 70861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt qi->home_realm_query_len = end - pos; 70961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (hapd->conf->nai_realm_data != NULL) { 71061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query " 71161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "(local)"); 71261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else { 71361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not " 71461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "available"); 71561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 71661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 71761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 71861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 71961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void rx_anqp_vendor_specific(struct hostapd_data *hapd, 72061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *pos, const u8 *end, 72161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct anqp_query_info *qi) 72261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 72361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u32 oui; 72461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 subtype; 72561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 72661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (pos + 4 > end) { 72761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP " 72861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "Query element"); 72961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return; 73061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 73161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 73261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt oui = WPA_GET_BE24(pos); 73361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos += 3; 73461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (oui != OUI_WFA) { 73561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x", 73661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt oui); 73761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return; 73861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 73961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 74061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (*pos != HS20_ANQP_OUI_TYPE) { 74161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u", 74261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt *pos); 74361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return; 74461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 74561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos++; 74661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 74761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (pos + 1 >= end) 74861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return; 74961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 75061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt subtype = *pos++; 75161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos++; /* Reserved */ 75261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt switch (subtype) { 75361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case HS20_STYPE_QUERY_LIST: 75461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List"); 75561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt while (pos < end) { 75661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rx_anqp_hs_query_list(hapd, *pos, qi); 75761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos++; 75861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 75961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 76061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case HS20_STYPE_NAI_HOME_REALM_QUERY: 76161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rx_anqp_hs_nai_home_realm(hapd, pos, end, qi); 76261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 76361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt default: 76461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype " 76561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "%u", subtype); 76661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 76761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 76861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 76961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 770aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */ 771aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt 77261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 77304949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_req_local_processing(struct hostapd_data *hapd, 77404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *sa, u8 dialog_token, 77504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct anqp_query_info *qi) 77604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 77704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *buf, *tx_buf; 77804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 77961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL, 78061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt qi->home_realm_query, 78161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt qi->home_realm_query_len); 78204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses", 78304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf); 78404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!buf) 78504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 78604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 78704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (wpabuf_len(buf) > hapd->gas_frag_limit || 78804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hapd->conf->gas_comeback_delay) { 78904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct gas_dialog_info *di; 79004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u16 comeback_delay = 1; 79104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 79204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hapd->conf->gas_comeback_delay) { 79304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Testing - allow overriding of the delay value */ 79404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt comeback_delay = hapd->conf->gas_comeback_delay; 79504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 79604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 79704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in " 79804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "initial response - use GAS comeback"); 79904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt di = gas_dialog_create(hapd, sa, dialog_token); 80004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!di) { 80104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_INFO, "ANQP: Could not create dialog " 80204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "for " MACSTR " (dialog token %u)", 80304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt MAC2STR(sa), dialog_token); 80404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(buf); 80504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 80604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 80704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt di->sd_resp = buf; 80804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt di->sd_resp_pos = 0; 80904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tx_buf = gas_anqp_build_initial_resp_buf( 81004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token, WLAN_STATUS_SUCCESS, comeback_delay, 81104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt NULL); 81204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } else { 81304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)"); 81404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tx_buf = gas_anqp_build_initial_resp_buf( 81504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token, WLAN_STATUS_SUCCESS, 0, buf); 81604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(buf); 81704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 81804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!tx_buf) 81904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 82004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 82104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, 82204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_head(tx_buf), wpabuf_len(tx_buf)); 82304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(tx_buf); 82404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 82504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 82604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 82704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd, 82804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *sa, 82904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *data, size_t len) 83004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 83104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *pos = data; 83204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *end = data + len; 83304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *next; 83404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 dialog_token; 83504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u16 slen; 83604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct anqp_query_info qi; 83704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *adv_proto; 83804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 83904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (len < 1 + 2) 84004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 84104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 84204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(&qi, 0, sizeof(qi)); 84304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 84404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token = *pos++; 84504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, 84604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "GAS: GAS Initial Request from " MACSTR " (dialog token %u) ", 84704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt MAC2STR(sa), dialog_token); 84804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 84904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (*pos != WLAN_EID_ADV_PROTO) { 85004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, 85104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "GAS: Unexpected IE in GAS Initial Request: %u", *pos); 85204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 85304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 85404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt adv_proto = pos++; 85504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 85604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt slen = *pos++; 85704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt next = pos + slen; 85804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (next > end || slen < 2) { 85904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, 86004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "GAS: Invalid IE in GAS Initial Request"); 86104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 86204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 86304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos++; /* skip QueryRespLenLimit and PAME-BI */ 86404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 86504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { 86604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *buf; 86704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, 86804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "GAS: Unsupported GAS advertisement protocol id %u", 86904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt *pos); 87004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sa[0] & 0x01) 87104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; /* Invalid source address - drop silently */ 87204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf = gas_build_initial_resp( 87304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED, 87404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 0, 2 + slen + 2); 87504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (buf == NULL) 87604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 87704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_data(buf, adv_proto, 2 + slen); 87804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_put_le16(buf, 0); /* Query Response Length */ 87904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, 88004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_head(buf), wpabuf_len(buf)); 88104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(buf); 88204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 88304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 88404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 88504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos = next; 88604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Query Request */ 88704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (pos + 2 > end) 88804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 88904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt slen = WPA_GET_LE16(pos); 89004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos += 2; 89104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (pos + slen > end) 89204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 89304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt end = pos + slen; 89404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 89504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* ANQP Query Request */ 89604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt while (pos < end) { 89704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u16 info_id, elen; 89804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 89904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (pos + 4 > end) 90004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 90104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 90204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt info_id = WPA_GET_LE16(pos); 90304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos += 2; 90404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt elen = WPA_GET_LE16(pos); 90504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos += 2; 90604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 90704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (pos + elen > end) { 90804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request"); 90904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 91004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 91104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 91204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt switch (info_id) { 91304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case ANQP_QUERY_LIST: 91404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt rx_anqp_query_list(hapd, pos, pos + elen, &qi); 91504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 916aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20 91761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case ANQP_VENDOR_SPECIFIC: 91861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi); 91961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 920aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */ 92104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt default: 92204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query " 92304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Request element %u", info_id); 92404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 92504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 92604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 92704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos += elen; 92804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 92904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 93004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_req_local_processing(hapd, sa, dialog_token, &qi); 93104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 93204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 93304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 93404949598a23f501be6eec21697465fd46a28840aDmitry Shmidtvoid gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst, 93504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct gas_dialog_info *dialog) 93604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 93704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *buf, *tx_buf; 93804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 dialog_token = dialog->dialog_token; 93904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t frag_len; 94004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 94104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (dialog->sd_resp == NULL) { 94204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf = gas_serv_build_gas_resp_payload(hapd, 94304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->all_requested, 94461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt dialog, NULL, 0); 94504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses", 94604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf); 94704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!buf) 94804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto tx_gas_response_done; 94904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp = buf; 95004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp_pos = 0; 95104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 95204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos; 95304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay || 95404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hapd->conf->gas_comeback_delay) { 95504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u16 comeback_delay_tus = dialog->comeback_delay + 95604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt GAS_SERV_COMEBACK_DELAY_FUDGE; 95704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u32 comeback_delay_secs, comeback_delay_usecs; 95804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 95904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hapd->conf->gas_comeback_delay) { 96004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Testing - allow overriding of the delay value */ 96104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt comeback_delay_tus = hapd->conf->gas_comeback_delay; 96204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 96304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 96404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit " 96504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "%u) and comeback delay %u, " 96604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "requesting comebacks", (unsigned int) frag_len, 96704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (unsigned int) hapd->gas_frag_limit, 96804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->comeback_delay); 96904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tx_buf = gas_anqp_build_initial_resp_buf(dialog_token, 97004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt WLAN_STATUS_SUCCESS, 97104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt comeback_delay_tus, 97204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt NULL); 97304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (tx_buf) { 97404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, 97504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "GAS: Tx GAS Initial Resp (comeback = 10TU)"); 97604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hostapd_drv_send_action(hapd, hapd->iface->freq, 0, 97704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dst, 97804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_head(tx_buf), 97904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_len(tx_buf)); 98004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 98104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(tx_buf); 98204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 98304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* start a timer of 1.5 * comeback-delay */ 98404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt comeback_delay_tus = comeback_delay_tus + 98504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (comeback_delay_tus / 2); 98604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000; 98704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt comeback_delay_usecs = (comeback_delay_tus * 1024) - 98804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (comeback_delay_secs * 1000000); 98904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt eloop_register_timeout(comeback_delay_secs, 99004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt comeback_delay_usecs, 99104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_clear_cached_ies, dialog, 99204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt NULL); 99304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto tx_gas_response_done; 99404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 99504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 99604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) + 99704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp_pos, frag_len); 99804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (buf == NULL) { 99904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation " 100004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "failed"); 100104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto tx_gas_response_done; 100204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 100304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tx_buf = gas_anqp_build_initial_resp_buf(dialog_token, 100404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt WLAN_STATUS_SUCCESS, 0, buf); 100504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(buf); 100604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (tx_buf == NULL) 100704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto tx_gas_response_done; 100804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial " 100904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Response (frag_id %d frag_len %d)", 101004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_frag_id, (int) frag_len); 101104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_frag_id++; 101204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 101304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst, 101404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_head(tx_buf), wpabuf_len(tx_buf)); 101504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(tx_buf); 101604949598a23f501be6eec21697465fd46a28840aDmitry Shmidttx_gas_response_done: 101704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_clear_cached_ies(dialog, NULL); 101804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 101904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 102004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 102104949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd, 102204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *sa, 102304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *data, size_t len) 102404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 102504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct gas_dialog_info *dialog; 102604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *buf, *tx_buf; 102704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 dialog_token; 102804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t frag_len; 102904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int more = 0; 103004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 103104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len); 103204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (len < 1) 103304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 103404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token = *data; 103504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u", 103604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token); 103704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 103804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog = gas_serv_dialog_find(hapd, sa, dialog_token); 103904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!dialog) { 104004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD " 104104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "response fragment for " MACSTR " dialog token %u", 104204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt MAC2STR(sa), dialog_token); 104304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 104404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (sa[0] & 0x01) 104504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; /* Invalid source address - drop silently */ 104604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tx_buf = gas_anqp_build_comeback_resp_buf( 104704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0, 104804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 0, NULL); 104904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (tx_buf == NULL) 105004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 105104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto send_resp; 105204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 105304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 105404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (dialog->sd_resp == NULL) { 105504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x", 105604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->requested, dialog->received); 105704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if ((dialog->requested & dialog->received) != 105804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->requested) { 105904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Did not receive response " 106004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "from remote processing"); 106104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_dialog_clear(dialog); 106204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tx_buf = gas_anqp_build_comeback_resp_buf( 106304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog_token, 106404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0, 106504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt NULL); 106604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (tx_buf == NULL) 106704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 106804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto send_resp; 106904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 107004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 107104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf = gas_serv_build_gas_resp_payload(hapd, 107204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->all_requested, 107361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt dialog, NULL, 0); 107404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses", 107504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf); 107604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!buf) 107704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto rx_gas_comeback_req_done; 107804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp = buf; 107904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp_pos = 0; 108004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 108104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos; 108204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (frag_len > hapd->gas_frag_limit) { 108304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt frag_len = hapd->gas_frag_limit; 108404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt more = 1; 108504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 108604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u", 108704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (unsigned int) frag_len); 108804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) + 108904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp_pos, frag_len); 109004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (buf == NULL) { 109104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate " 109204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "buffer"); 109304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto rx_gas_comeback_req_done; 109404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 109504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token, 109604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt WLAN_STATUS_SUCCESS, 109704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_frag_id, 109804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt more, 0, buf); 109904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(buf); 110004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (tx_buf == NULL) 110104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto rx_gas_comeback_req_done; 110204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response " 110304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "(frag_id %d more=%d frag_len=%d)", 110404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_frag_id, more, (int) frag_len); 110504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_frag_id++; 110604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp_pos += frag_len; 110704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 110804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (more) { 110904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain " 111004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "to be sent", 111104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (int) (wpabuf_len(dialog->sd_resp) - 111204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dialog->sd_resp_pos)); 111304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } else { 111404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of " 111504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "SD response sent"); 111604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_dialog_clear(dialog); 111704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_free_dialogs(hapd, sa); 111804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 111904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 112004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtsend_resp: 112104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, 112204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_head(tx_buf), wpabuf_len(tx_buf)); 112304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_free(tx_buf); 112404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 112504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 112604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtrx_gas_comeback_req_done: 112704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_clear_cached_ies(dialog, NULL); 112804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 112904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 113004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 113104949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len, 113204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int freq) 113304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 113404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_data *hapd = ctx; 113504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const struct ieee80211_mgmt *mgmt; 113604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t hdr_len; 113704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *sa, *data; 113804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 113904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt mgmt = (const struct ieee80211_mgmt *) buf; 114004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf; 114104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hdr_len > len) 114204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 114304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (mgmt->u.action.category != WLAN_ACTION_PUBLIC) 114404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 114504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sa = mgmt->sa; 114604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len -= hdr_len; 114704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt data = &mgmt->u.action.u.public_action.action; 114804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt switch (data[0]) { 114904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case WLAN_PA_GAS_INITIAL_REQ: 115004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1); 115104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 115204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case WLAN_PA_GAS_COMEBACK_REQ: 115304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1); 115404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 115504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 115604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 115704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 115804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 115904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint gas_serv_init(struct hostapd_data *hapd) 116004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 11614b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt hapd->public_action_cb2 = gas_serv_rx_public_action; 11624b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt hapd->public_action_cb2_ctx = hapd; 116304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hapd->gas_frag_limit = 1400; 116404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hapd->conf->gas_frag_limit > 0) 116504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hapd->gas_frag_limit = hapd->conf->gas_frag_limit; 116604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 0; 116704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 116804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 116904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 117004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtvoid gas_serv_deinit(struct hostapd_data *hapd) 117104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 117204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 1173