104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt/*
204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * Generic advertisement service (GAS) server
31846323989242844f0e857458a8939fa5836429cDmitry Shmidt * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt *
504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * This software may be distributed under the terms of the BSD license.
604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * See README for more details.
704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt */
804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "includes.h"
1004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
1104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "common.h"
1204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "common/ieee802_11_defs.h"
1304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "common/gas.h"
1404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "utils/eloop.h"
1504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "hostapd.h"
1604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "ap_config.h"
1704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "ap_drv_ops.h"
1804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "sta_info.h"
1904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "gas_serv.h"
2004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
2104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
221846323989242844f0e857458a8939fa5836429cDmitry Shmidtstatic void convert_to_protected_dual(struct wpabuf *msg)
231846323989242844f0e857458a8939fa5836429cDmitry Shmidt{
241846323989242844f0e857458a8939fa5836429cDmitry Shmidt	u8 *categ = wpabuf_mhead_u8(msg);
251846323989242844f0e857458a8939fa5836429cDmitry Shmidt	*categ = WLAN_ACTION_PROTECTED_DUAL;
261846323989242844f0e857458a8939fa5836429cDmitry Shmidt}
271846323989242844f0e857458a8939fa5836429cDmitry Shmidt
281846323989242844f0e857458a8939fa5836429cDmitry Shmidt
2904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic struct gas_dialog_info *
3004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtgas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
3104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
3204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct sta_info *sta;
3304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct gas_dialog_info *dia = NULL;
3404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	int i, j;
3504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
3604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	sta = ap_get_sta(hapd, addr);
3704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (!sta) {
3804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		/*
3904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		 * We need a STA entry to be able to maintain state for
4004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		 * the GAS query.
4104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		 */
4204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for "
4304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   "GAS query");
4404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		sta = ap_sta_add(hapd, addr);
4504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (!sta) {
4604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR
4704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				   " for GAS query", MAC2STR(addr));
4804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			return NULL;
4904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
5004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		sta->flags |= WLAN_STA_GAS;
5104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		/*
5204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		 * The default inactivity is 300 seconds. We don't need
5304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		 * it to be that long.
5404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		 */
5504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		ap_sta_session_timeout(hapd, sta, 5);
565460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	} else {
575460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		ap_sta_replenish_timeout(hapd, sta, 5);
5804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
5904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
6004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (sta->gas_dialog == NULL) {
6104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX *
6204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					    sizeof(struct gas_dialog_info));
6304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (sta->gas_dialog == NULL)
6404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			return NULL;
6504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
6604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
6704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) {
6804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (i == GAS_DIALOG_MAX)
6904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			i = 0;
7004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (sta->gas_dialog[i].valid)
7104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			continue;
7204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		dia = &sta->gas_dialog[i];
7304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		dia->valid = 1;
7404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		dia->dialog_token = dialog_token;
7504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i;
7604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return dia;
7704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
7804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
7904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_msg(hapd->msg_ctx, MSG_ERROR, "ANQP: Could not create dialog for "
8004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		MACSTR " dialog_token %u. Consider increasing "
8104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		"GAS_DIALOG_MAX.", MAC2STR(addr), dialog_token);
8204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
8304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return NULL;
8404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
8504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
8604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
8704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct gas_dialog_info *
8804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtgas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
8904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		     u8 dialog_token)
9004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
9104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct sta_info *sta;
9204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	int i;
9304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
9404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	sta = ap_get_sta(hapd, addr);
9504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (!sta) {
9604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR,
9704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   MAC2STR(addr));
9804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
9904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
10004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	for (i = 0; sta->gas_dialog && i < GAS_DIALOG_MAX; i++) {
10104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (sta->gas_dialog[i].dialog_token != dialog_token ||
10204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		    !sta->gas_dialog[i].valid)
10304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			continue;
10404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return &sta->gas_dialog[i];
10504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
10604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
10704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		   MACSTR " dialog_token %u", MAC2STR(addr), dialog_token);
10804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return NULL;
10904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
11004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
11104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
11204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtvoid gas_serv_dialog_clear(struct gas_dialog_info *dia)
11304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
11404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpabuf_free(dia->sd_resp);
11504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	os_memset(dia, 0, sizeof(*dia));
11604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
11704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
11804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
11904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_free_dialogs(struct hostapd_data *hapd,
12004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				  const u8 *sta_addr)
12104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
12204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct sta_info *sta;
12304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	int i;
12404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
12504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	sta = ap_get_sta(hapd, sta_addr);
12604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (sta == NULL || sta->gas_dialog == NULL)
12704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return;
12804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
12904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	for (i = 0; i < GAS_DIALOG_MAX; i++) {
13004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (sta->gas_dialog[i].valid)
13104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			return;
13204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
13304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
13404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	os_free(sta->gas_dialog);
13504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	sta->gas_dialog = NULL;
13604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
13704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
13804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
139aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20
14061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_hs_capab_list(struct hostapd_data *hapd,
14161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				   struct wpabuf *buf)
14261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
14361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	u8 *len;
14461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
14561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
14661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpabuf_put_be24(buf, OUI_WFA);
14761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
14861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
14961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpabuf_put_u8(buf, 0); /* Reserved */
15061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
15161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->hs20_oper_friendly_name)
15261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
15361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->hs20_wan_metrics)
15461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
15561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->hs20_connection_capability)
15661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
15761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->nai_realm_data)
15861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
15961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->hs20_operating_class)
16061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
161f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (hapd->conf->hs20_osu_providers_count)
162f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
163f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (hapd->conf->hs20_icons_count)
164f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
16561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	gas_anqp_set_element_len(buf, len);
16661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
167aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */
16861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
16961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
17004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void anqp_add_capab_list(struct hostapd_data *hapd,
17104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				struct wpabuf *buf)
17204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
17304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u8 *len;
17404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
17504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
17604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
17704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (hapd->conf->venue_name)
17804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_put_le16(buf, ANQP_VENUE_NAME);
17961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->network_auth_type)
18061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
18104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (hapd->conf->roaming_consortium)
18204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
18361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->ipaddr_type_configured)
18461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
18561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->nai_realm_data)
18661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf, ANQP_NAI_REALM);
18761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->anqp_3gpp_cell_net)
18861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
18961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->domain_name)
19061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
191aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20
19261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	anqp_add_hs_capab_list(hapd, buf);
193aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */
19404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	gas_anqp_set_element_len(buf, len);
19504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
19604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
19704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
19804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
19904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
20004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (hapd->conf->venue_name) {
20104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		u8 *len;
20204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		unsigned int i;
20304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		len = gas_anqp_add_element(buf, ANQP_VENUE_NAME);
20404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_put_u8(buf, hapd->conf->venue_group);
20504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_put_u8(buf, hapd->conf->venue_type);
20604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		for (i = 0; i < hapd->conf->venue_name_count; i++) {
20761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			struct hostapd_lang_string *vn;
20804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			vn = &hapd->conf->venue_name[i];
20904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpabuf_put_u8(buf, 3 + vn->name_len);
21004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpabuf_put_data(buf, vn->lang, 3);
21104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpabuf_put_data(buf, vn->name, vn->name_len);
21204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
21304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		gas_anqp_set_element_len(buf, len);
21404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
21504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
21604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
21704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
21861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_network_auth_type(struct hostapd_data *hapd,
21961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				       struct wpabuf *buf)
22061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
22161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->network_auth_type) {
22261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
22361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
22461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_data(buf, hapd->conf->network_auth_type,
22561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				hapd->conf->network_auth_type_len);
22661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
22761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
22861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
22961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
23004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void anqp_add_roaming_consortium(struct hostapd_data *hapd,
23104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					struct wpabuf *buf)
23204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
23304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	unsigned int i;
23404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u8 *len;
23504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
23604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
23704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
23804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		struct hostapd_roaming_consortium *rc;
23904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		rc = &hapd->conf->roaming_consortium[i];
24004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_put_u8(buf, rc->len);
24104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_put_data(buf, rc->oi, rc->len);
24204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
24304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	gas_anqp_set_element_len(buf, len);
24404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
24504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
24604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
24761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
24861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					       struct wpabuf *buf)
24961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
25061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->ipaddr_type_configured) {
25161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
25261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf, 1);
25361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, hapd->conf->ipaddr_type_availability);
25461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
25561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
25661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
25761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
25861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_nai_realm_eap(struct wpabuf *buf,
25961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				   struct hostapd_nai_realm_data *realm)
26061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
26161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	unsigned int i, j;
26261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
26361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpabuf_put_u8(buf, realm->eap_method_count);
26461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
26561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	for (i = 0; i < realm->eap_method_count; i++) {
26661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		struct hostapd_nai_realm_eap *eap = &realm->eap_method[i];
26761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, 2 + (3 * eap->num_auths));
26861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, eap->eap_method);
26961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, eap->num_auths);
27061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		for (j = 0; j < eap->num_auths; j++) {
27161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpabuf_put_u8(buf, eap->auth_id[j]);
27261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpabuf_put_u8(buf, 1);
27361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpabuf_put_u8(buf, eap->auth_val[j]);
27461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
27561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
27661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
27761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
27861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
27961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_nai_realm_data(struct wpabuf *buf,
28061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				    struct hostapd_nai_realm_data *realm,
28161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				    unsigned int realm_idx)
28261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
28361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	u8 *realm_data_len;
28461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
28561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx],
28661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		   (int) os_strlen(realm->realm[realm_idx]));
28761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	realm_data_len = wpabuf_put(buf, 2);
28861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpabuf_put_u8(buf, realm->encoding);
28961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx]));
29061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpabuf_put_str(buf, realm->realm[realm_idx]);
29161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	anqp_add_nai_realm_eap(buf, realm);
29261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	gas_anqp_set_element_len(buf, realm_data_len);
29361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
29461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
29561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
29661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
29761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					   struct wpabuf *buf,
29861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					   const u8 *home_realm,
29961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					   size_t home_realm_len)
30061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
30161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	unsigned int i, j, k;
30261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len;
30361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct hostapd_nai_realm_data *realm;
30461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	const u8 *pos, *realm_name, *end;
30561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct {
30661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		unsigned int realm_data_idx;
30761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		unsigned int realm_idx;
30861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	} matches[10];
30961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
31061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	pos = home_realm;
31161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	end = pos + home_realm_len;
31261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (pos + 1 > end) {
31361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
31461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			    home_realm, home_realm_len);
31561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
31661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
31761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	num_realms = *pos++;
31861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
31961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	for (i = 0; i < num_realms && num_matching < 10; i++) {
32061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (pos + 2 > end) {
32161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpa_hexdump(MSG_DEBUG,
32261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				    "Truncated NAI Home Realm Query",
32361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				    home_realm, home_realm_len);
32461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			return -1;
32561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
32661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		encoding = *pos++;
32761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		realm_len = *pos++;
32861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (pos + realm_len > end) {
32961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpa_hexdump(MSG_DEBUG,
33061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				    "Truncated NAI Home Realm Query",
33161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				    home_realm, home_realm_len);
33261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			return -1;
33361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
33461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		realm_name = pos;
33561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		for (j = 0; j < hapd->conf->nai_realm_count &&
33661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			     num_matching < 10; j++) {
33761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			const u8 *rpos, *rend;
33861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			realm = &hapd->conf->nai_realm_data[j];
33961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			if (encoding != realm->encoding)
34061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				continue;
34161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
34261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			rpos = realm_name;
34361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			while (rpos < realm_name + realm_len &&
34461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			       num_matching < 10) {
34561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				for (rend = rpos;
34661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				     rend < realm_name + realm_len; rend++) {
34761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					if (*rend == ';')
34861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt						break;
34961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				}
35061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				for (k = 0; k < MAX_NAI_REALMS &&
35161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					     realm->realm[k] &&
35261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					     num_matching < 10; k++) {
35361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					if ((int) os_strlen(realm->realm[k]) !=
35461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					    rend - rpos ||
35561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					    os_strncmp((char *) rpos,
35661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt						       realm->realm[k],
35761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt						       rend - rpos) != 0)
35861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt						continue;
35961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					matches[num_matching].realm_data_idx =
36061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt						j;
36161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					matches[num_matching].realm_idx = k;
36261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					num_matching++;
36361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				}
36461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				rpos = rend + 1;
36561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			}
36661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
36761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		pos += realm_len;
36861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
36961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
37061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
37161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpabuf_put_le16(buf, num_matching);
37261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
37361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	/*
37461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * There are two ways to format. 1. each realm in a NAI Realm Data unit
37561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * 2. all realms that share the same EAP methods in a NAI Realm Data
37661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * unit. The first format is likely to be bigger in size than the
37761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * second, but may be easier to parse and process by the receiver.
37861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 */
37961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	for (i = 0; i < num_matching; i++) {
38061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d",
38161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   matches[i].realm_data_idx, matches[i].realm_idx);
38261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx];
38361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx);
38461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
38561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	gas_anqp_set_element_len(buf, realm_list_len);
38661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return 0;
38761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
38861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
38961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
39061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
39161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			       const u8 *home_realm, size_t home_realm_len,
39261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			       int nai_realm, int nai_home_realm)
39361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
39461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (nai_realm && hapd->conf->nai_realm_data) {
39561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		u8 *len;
39661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		unsigned int i, j;
39761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
39861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf, hapd->conf->nai_realm_count);
39961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		for (i = 0; i < hapd->conf->nai_realm_count; i++) {
40061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			u8 *realm_data_len, *realm_len;
40161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			struct hostapd_nai_realm_data *realm;
40261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
40361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			realm = &hapd->conf->nai_realm_data[i];
40461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			realm_data_len = wpabuf_put(buf, 2);
40561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpabuf_put_u8(buf, realm->encoding);
40661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			realm_len = wpabuf_put(buf, 1);
40761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			for (j = 0; realm->realm[j]; j++) {
40861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				if (j > 0)
40961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					wpabuf_put_u8(buf, ';');
41061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				wpabuf_put_str(buf, realm->realm[j]);
41161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			}
41261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			*realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1;
41361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			anqp_add_nai_realm_eap(buf, realm);
41461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			gas_anqp_set_element_len(buf, realm_data_len);
41561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
41661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		gas_anqp_set_element_len(buf, len);
41709f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt	} else if (nai_home_realm && hapd->conf->nai_realm_data && home_realm) {
41861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
41961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt						home_realm_len);
42061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
42161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
42261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
42361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
42461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
42561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					   struct wpabuf *buf)
42661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
42761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->anqp_3gpp_cell_net) {
42861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
42961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf,
43061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				hapd->conf->anqp_3gpp_cell_net_len);
43161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net,
43261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				hapd->conf->anqp_3gpp_cell_net_len);
43361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
43461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
43561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
43661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
43761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
43861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
43961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->domain_name) {
44061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
44161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf, hapd->conf->domain_name_len);
44261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_data(buf, hapd->conf->domain_name,
44361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				hapd->conf->domain_name_len);
44461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
44561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
44661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
44761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
448aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20
449aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt
45061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
45161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					    struct wpabuf *buf)
45261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
45361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->hs20_oper_friendly_name) {
45461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		u8 *len;
45561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		unsigned int i;
45661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
45761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_be24(buf, OUI_WFA);
45861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
45961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
46061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, 0); /* Reserved */
46161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++)
46261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		{
46361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			struct hostapd_lang_string *vn;
46461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			vn = &hapd->conf->hs20_oper_friendly_name[i];
46561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpabuf_put_u8(buf, 3 + vn->name_len);
46661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpabuf_put_data(buf, vn->lang, 3);
46761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpabuf_put_data(buf, vn->name, vn->name_len);
46861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
46961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		gas_anqp_set_element_len(buf, len);
47061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
47161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
47261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
47361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
47461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_wan_metrics(struct hostapd_data *hapd,
47561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				 struct wpabuf *buf)
47661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
47761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->hs20_wan_metrics) {
47861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
47961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_be24(buf, OUI_WFA);
48061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
48161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
48261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, 0); /* Reserved */
48361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13);
48461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		gas_anqp_set_element_len(buf, len);
48561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
48661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
48761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
48861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
48961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_connection_capability(struct hostapd_data *hapd,
49061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					   struct wpabuf *buf)
49161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
49261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->hs20_connection_capability) {
49361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
49461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_be24(buf, OUI_WFA);
49561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
49661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
49761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, 0); /* Reserved */
49861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_data(buf, hapd->conf->hs20_connection_capability,
49961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				hapd->conf->hs20_connection_capability_len);
50061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		gas_anqp_set_element_len(buf, len);
50161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
50261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
50361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
50461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
50561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void anqp_add_operating_class(struct hostapd_data *hapd,
50661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				     struct wpabuf *buf)
50761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
50861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->hs20_operating_class) {
50961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
51061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_be24(buf, OUI_WFA);
51161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
51261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
51361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(buf, 0); /* Reserved */
51461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_data(buf, hapd->conf->hs20_operating_class,
51561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				hapd->conf->hs20_operating_class_len);
51661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		gas_anqp_set_element_len(buf, len);
51761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
51861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
51961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
520f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
521f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic void anqp_add_osu_provider(struct wpabuf *buf,
522f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				  struct hostapd_bss_config *bss,
523f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				  struct hs20_osu_provider *p)
524f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
525f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	u8 *len, *len2, *count;
526f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	unsigned int i;
527f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
528f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	len = wpabuf_put(buf, 2); /* OSU Provider Length to be filled */
529f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
530f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* OSU Friendly Name Duples */
531f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	len2 = wpabuf_put(buf, 2);
532f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (i = 0; i < p->friendly_name_count; i++) {
533f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		struct hostapd_lang_string *s = &p->friendly_name[i];
534f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, 3 + s->name_len);
535f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_data(buf, s->lang, 3);
536f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_data(buf, s->name, s->name_len);
537f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
538f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
539f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
540f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* OSU Server URI */
541f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (p->server_uri) {
542f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, os_strlen(p->server_uri));
543f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_str(buf, p->server_uri);
544f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	} else
545f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, 0);
546f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
547f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* OSU Method List */
548f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	count = wpabuf_put(buf, 1);
549f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (i = 0; p->method_list[i] >= 0; i++)
550f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, p->method_list[i]);
551f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	*count = i;
552f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
553f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* Icons Available */
554f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	len2 = wpabuf_put(buf, 2);
555f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (i = 0; i < p->icons_count; i++) {
556f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		size_t j;
557f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		struct hs20_icon *icon = NULL;
558f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
559f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
560f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (os_strcmp(p->icons[i], bss->hs20_icons[j].name) ==
561f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			    0)
562f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				icon = &bss->hs20_icons[j];
563f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		}
564f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (!icon)
565f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			continue; /* icon info not found */
566f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
567f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_le16(buf, icon->width);
568f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_le16(buf, icon->height);
569f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_data(buf, icon->language, 3);
570f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, os_strlen(icon->type));
571f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_str(buf, icon->type);
572f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, os_strlen(icon->name));
573f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_str(buf, icon->name);
574f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
575f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
576f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
577f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* OSU_NAI */
578f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (p->osu_nai) {
579f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, os_strlen(p->osu_nai));
580f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_str(buf, p->osu_nai);
581f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	} else
582f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, 0);
583f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
584f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* OSU Service Description Duples */
585f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	len2 = wpabuf_put(buf, 2);
586f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (i = 0; i < p->service_desc_count; i++) {
587f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		struct hostapd_lang_string *s = &p->service_desc[i];
588f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, 3 + s->name_len);
589f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_data(buf, s->lang, 3);
590f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_data(buf, s->name, s->name_len);
591f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
592f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
593f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
594f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
595f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
596f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
597f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
598f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic void anqp_add_osu_providers_list(struct hostapd_data *hapd,
599f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					struct wpabuf *buf)
600f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
601f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (hapd->conf->hs20_osu_providers_count) {
602f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		size_t i;
603f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
604f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_be24(buf, OUI_WFA);
605f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
606f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
607f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, 0); /* Reserved */
608f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
609f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		/* OSU SSID */
610f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, hapd->conf->osu_ssid_len);
611f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_data(buf, hapd->conf->osu_ssid,
612f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				hapd->conf->osu_ssid_len);
613f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
614f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		/* Number of OSU Providers */
615f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, hapd->conf->hs20_osu_providers_count);
616f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
617f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
618f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			anqp_add_osu_provider(
619f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				buf, hapd->conf,
620f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				&hapd->conf->hs20_osu_providers[i]);
621f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		}
622f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
623f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		gas_anqp_set_element_len(buf, len);
624f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
625f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
626f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
627f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
628f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic void anqp_add_icon_binary_file(struct hostapd_data *hapd,
629f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				      struct wpabuf *buf,
630f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				      const u8 *name, size_t name_len)
631f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
632f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct hs20_icon *icon;
633f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	size_t i;
634f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	u8 *len;
635f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
636f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "HS 2.0: Requested Icon Filename",
637f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			  name, name_len);
638f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (i = 0; i < hapd->conf->hs20_icons_count; i++) {
639f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		icon = &hapd->conf->hs20_icons[i];
640f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (name_len == os_strlen(icon->name) &&
641f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		    os_memcmp(name, icon->name, name_len) == 0)
642f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			break;
643f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
644f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
645f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (i < hapd->conf->hs20_icons_count)
646f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		icon = &hapd->conf->hs20_icons[i];
647f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	else
648f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		icon = NULL;
649f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
650f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
651f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpabuf_put_be24(buf, OUI_WFA);
652f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
653f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpabuf_put_u8(buf, HS20_STYPE_ICON_BINARY_FILE);
654f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpabuf_put_u8(buf, 0); /* Reserved */
655f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
656f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (icon) {
657f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		char *data;
658f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		size_t data_len;
659f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
660f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		data = os_readfile(icon->file, &data_len);
661f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (data == NULL || data_len > 65535) {
662f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpabuf_put_u8(buf, 2); /* Download Status:
663f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt						* Unspecified file error */
664f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpabuf_put_u8(buf, 0);
665f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpabuf_put_le16(buf, 0);
666f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		} else {
667f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpabuf_put_u8(buf, 0); /* Download Status: Success */
668f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpabuf_put_u8(buf, os_strlen(icon->type));
669f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpabuf_put_str(buf, icon->type);
670f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpabuf_put_le16(buf, data_len);
671f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpabuf_put_data(buf, data, data_len);
672f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		}
673f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		os_free(data);
674f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	} else {
675f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, 1); /* Download Status: File not found */
676f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_u8(buf, 0);
677f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpabuf_put_le16(buf, 0);
678f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
679f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
680f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	gas_anqp_set_element_len(buf, len);
681f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
682f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
683aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */
684aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt
68561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
68604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic struct wpabuf *
68704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtgas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
68804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				unsigned int request,
689f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				const u8 *home_realm, size_t home_realm_len,
690f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				const u8 *icon_name, size_t icon_name_len)
69104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
69204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpabuf *buf;
693f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	size_t len;
694f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
695f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	len = 1400;
696f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
697f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		len += 1000;
698f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (request & ANQP_REQ_ICON_REQUEST)
699f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		len += 65536;
70004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
701f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	buf = wpabuf_alloc(len);
70204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (buf == NULL)
70304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
70404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
70504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (request & ANQP_REQ_CAPABILITY_LIST)
70604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		anqp_add_capab_list(hapd, buf);
70704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (request & ANQP_REQ_VENUE_NAME)
70804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		anqp_add_venue_name(hapd, buf);
70961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
71061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		anqp_add_network_auth_type(hapd, buf);
71104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (request & ANQP_REQ_ROAMING_CONSORTIUM)
71204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		anqp_add_roaming_consortium(hapd, buf);
71361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY)
71461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		anqp_add_ip_addr_type_availability(hapd, buf);
71561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
71661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len,
71761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				   request & ANQP_REQ_NAI_REALM,
71861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				   request & ANQP_REQ_NAI_HOME_REALM);
71961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
72061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		anqp_add_3gpp_cellular_network(hapd, buf);
72161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (request & ANQP_REQ_DOMAIN_NAME)
72261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		anqp_add_domain_name(hapd, buf);
72361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
724aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20
72561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (request & ANQP_REQ_HS_CAPABILITY_LIST)
72661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		anqp_add_hs_capab_list(hapd, buf);
72761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (request & ANQP_REQ_OPERATOR_FRIENDLY_NAME)
72861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		anqp_add_operator_friendly_name(hapd, buf);
72961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (request & ANQP_REQ_WAN_METRICS)
73061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		anqp_add_wan_metrics(hapd, buf);
73161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (request & ANQP_REQ_CONNECTION_CAPABILITY)
73261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		anqp_add_connection_capability(hapd, buf);
73361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (request & ANQP_REQ_OPERATING_CLASS)
73461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		anqp_add_operating_class(hapd, buf);
735f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (request & ANQP_REQ_OSU_PROVIDERS_LIST)
736f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		anqp_add_osu_providers_list(hapd, buf);
737f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (request & ANQP_REQ_ICON_REQUEST)
738f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		anqp_add_icon_binary_file(hapd, buf, icon_name, icon_name_len);
739aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */
74004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
74104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return buf;
74204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
74304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
74404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
74504949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct anqp_query_info {
74604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	unsigned int request;
74761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	const u8 *home_realm_query;
74861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	size_t home_realm_query_len;
749f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	const u8 *icon_name;
750f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	size_t icon_name_len;
75104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt};
75204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
75304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
75404949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void set_anqp_req(unsigned int bit, const char *name, int local,
75504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			 struct anqp_query_info *qi)
75604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
75704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	qi->request |= bit;
75804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (local) {
75904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name);
76004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	} else {
76104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: %s not available", name);
76204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
76304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
76404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
76504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
76604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
76704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				  struct anqp_query_info *qi)
76804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
76904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	switch (info_id) {
77004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	case ANQP_CAPABILITY_LIST:
771b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1,
772b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			     qi);
77304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		break;
77404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	case ANQP_VENUE_NAME:
77504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
776b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			     hapd->conf->venue_name != NULL, qi);
77704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		break;
77861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case ANQP_NETWORK_AUTH_TYPE:
77961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
780b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			     hapd->conf->network_auth_type != NULL, qi);
78161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
78204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	case ANQP_ROAMING_CONSORTIUM:
78304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
784b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			     hapd->conf->roaming_consortium != NULL, qi);
78504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		break;
78661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case ANQP_IP_ADDR_TYPE_AVAILABILITY:
78761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY,
78861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			     "IP Addr Type Availability",
789b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			     hapd->conf->ipaddr_type_configured, qi);
79061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
79161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case ANQP_NAI_REALM:
79261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm",
793b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			     hapd->conf->nai_realm_data != NULL, qi);
79461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
79561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case ANQP_3GPP_CELLULAR_NETWORK:
79661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
79761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			     "3GPP Cellular Network",
798b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			     hapd->conf->anqp_3gpp_cell_net != NULL, qi);
79961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
80061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case ANQP_DOMAIN_NAME:
80161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
802b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			     hapd->conf->domain_name != NULL, qi);
80361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
80404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	default:
80504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
80604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   info_id);
80704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		break;
80804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
80904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
81004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
81104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
81204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void rx_anqp_query_list(struct hostapd_data *hapd,
81304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			       const u8 *pos, const u8 *end,
81404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			       struct anqp_query_info *qi)
81504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
81604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
81704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		   (unsigned int) (end - pos) / 2);
81804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
81904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	while (pos + 2 <= end) {
82004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
82104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		pos += 2;
82204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
82304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
82404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
82504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
826aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20
827aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt
82861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
82961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				  struct anqp_query_info *qi)
83061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
83161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	switch (subtype) {
83261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case HS20_STYPE_CAPABILITY_LIST:
83361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List",
834b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			     1, qi);
83561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
83661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
83761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME,
83861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			     "Operator Friendly Name",
839b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			     hapd->conf->hs20_oper_friendly_name != NULL, qi);
84061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
84161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case HS20_STYPE_WAN_METRICS:
84261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics",
843b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			     hapd->conf->hs20_wan_metrics != NULL, qi);
84461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
84561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case HS20_STYPE_CONNECTION_CAPABILITY:
84661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY,
84761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			     "Connection Capability",
84861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			     hapd->conf->hs20_connection_capability != NULL,
849b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			     qi);
85061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
85161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case HS20_STYPE_OPERATING_CLASS:
85261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class",
853b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			     hapd->conf->hs20_operating_class != NULL, qi);
85461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
855f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	case HS20_STYPE_OSU_PROVIDERS_LIST:
856f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list",
857b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			     hapd->conf->hs20_osu_providers_count, qi);
858f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		break;
85961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	default:
86061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
86161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   subtype);
86261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
86361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
86461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
86561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
86661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
86761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd,
86861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				      const u8 *pos, const u8 *end,
86961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				      struct anqp_query_info *qi)
87061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
87161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	qi->request |= ANQP_REQ_NAI_HOME_REALM;
87261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	qi->home_realm_query = pos;
87361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	qi->home_realm_query_len = end - pos;
87461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (hapd->conf->nai_realm_data != NULL) {
87561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query "
87661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   "(local)");
87761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	} else {
87861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not "
87961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   "available");
88061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
88161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
88261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
88361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
884f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic void rx_anqp_hs_icon_request(struct hostapd_data *hapd,
885f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				    const u8 *pos, const u8 *end,
886f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				    struct anqp_query_info *qi)
887f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
888f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	qi->request |= ANQP_REQ_ICON_REQUEST;
889f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	qi->icon_name = pos;
890f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	qi->icon_name_len = end - pos;
891f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (hapd->conf->hs20_icons_count) {
892f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query "
893f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   "(local)");
894f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	} else {
895f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query not "
896f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   "available");
897f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
898f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
899f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
900f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
90161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void rx_anqp_vendor_specific(struct hostapd_data *hapd,
90261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				    const u8 *pos, const u8 *end,
90361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				    struct anqp_query_info *qi)
90461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
90561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	u32 oui;
90661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	u8 subtype;
90761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
90861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (pos + 4 > end) {
90961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
91061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   "Query element");
91161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return;
91261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
91361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
91461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	oui = WPA_GET_BE24(pos);
91561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	pos += 3;
91661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (oui != OUI_WFA) {
91761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
91861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   oui);
91961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return;
92061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
92161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
92261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (*pos != HS20_ANQP_OUI_TYPE) {
92361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
92461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   *pos);
92561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return;
92661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
92761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	pos++;
92861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
92961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (pos + 1 >= end)
93061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return;
93161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
93261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	subtype = *pos++;
93361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	pos++; /* Reserved */
93461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	switch (subtype) {
93561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case HS20_STYPE_QUERY_LIST:
93661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List");
93761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		while (pos < end) {
93861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			rx_anqp_hs_query_list(hapd, *pos, qi);
93961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			pos++;
94061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
94161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
94261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case HS20_STYPE_NAI_HOME_REALM_QUERY:
94361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		rx_anqp_hs_nai_home_realm(hapd, pos, end, qi);
94461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
945f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	case HS20_STYPE_ICON_REQUEST:
946f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		rx_anqp_hs_icon_request(hapd, pos, end, qi);
947f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		break;
94861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	default:
94961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype "
95061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   "%u", subtype);
95161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
95261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
95361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
95461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
955aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */
956aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt
95761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
95804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_req_local_processing(struct hostapd_data *hapd,
95904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					  const u8 *sa, u8 dialog_token,
9601846323989242844f0e857458a8939fa5836429cDmitry Shmidt					  struct anqp_query_info *qi, int prot)
96104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
96204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpabuf *buf, *tx_buf;
96304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
96409f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt	buf = gas_serv_build_gas_resp_payload(hapd, qi->request,
96561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					      qi->home_realm_query,
966f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					      qi->home_realm_query_len,
967f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					      qi->icon_name, qi->icon_name_len);
96804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
96904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			buf);
97004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (!buf)
97104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return;
97204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
97304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (wpabuf_len(buf) > hapd->gas_frag_limit ||
97404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	    hapd->conf->gas_comeback_delay) {
97504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		struct gas_dialog_info *di;
97604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		u16 comeback_delay = 1;
97704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
97804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (hapd->conf->gas_comeback_delay) {
97904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			/* Testing - allow overriding of the delay value */
98004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			comeback_delay = hapd->conf->gas_comeback_delay;
98104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
98204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
98304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in "
98404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   "initial response - use GAS comeback");
98504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		di = gas_dialog_create(hapd, sa, dialog_token);
98604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (!di) {
98704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpa_printf(MSG_INFO, "ANQP: Could not create dialog "
98804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				   "for " MACSTR " (dialog token %u)",
98904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				   MAC2STR(sa), dialog_token);
99004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpabuf_free(buf);
99176cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt			tx_buf = gas_anqp_build_initial_resp_buf(
99276cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt				dialog_token, WLAN_STATUS_UNSPECIFIED_FAILURE,
99376cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt				0, NULL);
99476cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt		} else {
99576cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt			di->prot = prot;
99676cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt			di->sd_resp = buf;
99776cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt			di->sd_resp_pos = 0;
99876cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt			tx_buf = gas_anqp_build_initial_resp_buf(
99976cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt				dialog_token, WLAN_STATUS_SUCCESS,
100076cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt				comeback_delay, NULL);
100104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
100204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	} else {
100304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)");
100404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		tx_buf = gas_anqp_build_initial_resp_buf(
100504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			dialog_token, WLAN_STATUS_SUCCESS, 0, buf);
100604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_free(buf);
100704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
100804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (!tx_buf)
100904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return;
10101846323989242844f0e857458a8939fa5836429cDmitry Shmidt	if (prot)
10111846323989242844f0e857458a8939fa5836429cDmitry Shmidt		convert_to_protected_dual(tx_buf);
101204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
101304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
101404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpabuf_free(tx_buf);
101504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
101604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
101704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
101804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
101904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					const u8 *sa,
10201846323989242844f0e857458a8939fa5836429cDmitry Shmidt					const u8 *data, size_t len, int prot)
102104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
102204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	const u8 *pos = data;
102304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	const u8 *end = data + len;
102404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	const u8 *next;
102504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u8 dialog_token;
102604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u16 slen;
102704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct anqp_query_info qi;
102804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	const u8 *adv_proto;
102904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
103004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (len < 1 + 2)
103104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return;
103204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
103304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	os_memset(&qi, 0, sizeof(qi));
103404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
103504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	dialog_token = *pos++;
103604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_msg(hapd->msg_ctx, MSG_DEBUG,
103704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		"GAS: GAS Initial Request from " MACSTR " (dialog token %u) ",
103804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		MAC2STR(sa), dialog_token);
103904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
104004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (*pos != WLAN_EID_ADV_PROTO) {
104104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
104204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			"GAS: Unexpected IE in GAS Initial Request: %u", *pos);
104304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return;
104404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
104504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	adv_proto = pos++;
104604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
104704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	slen = *pos++;
104804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	next = pos + slen;
104904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (next > end || slen < 2) {
105004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
105104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			"GAS: Invalid IE in GAS Initial Request");
105204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return;
105304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
105404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	pos++; /* skip QueryRespLenLimit and PAME-BI */
105504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
105604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
105704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		struct wpabuf *buf;
105804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
105904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			"GAS: Unsupported GAS advertisement protocol id %u",
106004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			*pos);
106104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (sa[0] & 0x01)
106204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			return; /* Invalid source address - drop silently */
106304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		buf = gas_build_initial_resp(
106404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED,
106504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			0, 2 + slen + 2);
106604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (buf == NULL)
106704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			return;
106804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_put_data(buf, adv_proto, 2 + slen);
106904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_put_le16(buf, 0); /* Query Response Length */
10701846323989242844f0e857458a8939fa5836429cDmitry Shmidt		if (prot)
10711846323989242844f0e857458a8939fa5836429cDmitry Shmidt			convert_to_protected_dual(buf);
107204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
107304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					wpabuf_head(buf), wpabuf_len(buf));
107404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_free(buf);
107504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return;
107604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
107704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
107804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	pos = next;
107904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	/* Query Request */
108004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (pos + 2 > end)
108104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return;
108204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	slen = WPA_GET_LE16(pos);
108304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	pos += 2;
108404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (pos + slen > end)
108504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return;
108604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	end = pos + slen;
108704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
108804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	/* ANQP Query Request */
108904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	while (pos < end) {
109004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		u16 info_id, elen;
109104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
109204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (pos + 4 > end)
109304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			return;
109404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
109504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		info_id = WPA_GET_LE16(pos);
109604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		pos += 2;
109704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		elen = WPA_GET_LE16(pos);
109804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		pos += 2;
109904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
110004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (pos + elen > end) {
110104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
110204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			return;
110304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
110404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
110504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		switch (info_id) {
110604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		case ANQP_QUERY_LIST:
110704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			rx_anqp_query_list(hapd, pos, pos + elen, &qi);
110804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			break;
1109aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#ifdef CONFIG_HS20
111061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		case ANQP_VENDOR_SPECIFIC:
111161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi);
111261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			break;
1113aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt#endif /* CONFIG_HS20 */
111404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		default:
111504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
111604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				   "Request element %u", info_id);
111704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			break;
111804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
111904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
112004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		pos += elen;
112104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
112204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
11231846323989242844f0e857458a8939fa5836429cDmitry Shmidt	gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot);
112404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
112504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
112604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
112704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
112804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					 const u8 *sa,
11291846323989242844f0e857458a8939fa5836429cDmitry Shmidt					 const u8 *data, size_t len, int prot)
113004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
113104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct gas_dialog_info *dialog;
113204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpabuf *buf, *tx_buf;
113304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u8 dialog_token;
113404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	size_t frag_len;
113504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	int more = 0;
113604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
113704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len);
113804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (len < 1)
113904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return;
114004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	dialog_token = *data;
114104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u",
114204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		dialog_token);
114304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
114404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	dialog = gas_serv_dialog_find(hapd, sa, dialog_token);
114504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (!dialog) {
114604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD "
114704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			"response fragment for " MACSTR " dialog token %u",
114804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			MAC2STR(sa), dialog_token);
114904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
115004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (sa[0] & 0x01)
115104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			return; /* Invalid source address - drop silently */
115204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		tx_buf = gas_anqp_build_comeback_resp_buf(
115304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0,
115404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			0, NULL);
115504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (tx_buf == NULL)
115604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			return;
115704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		goto send_resp;
115804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
115904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
116004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
116104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (frag_len > hapd->gas_frag_limit) {
116204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		frag_len = hapd->gas_frag_limit;
116304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		more = 1;
116404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
116504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
116604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		(unsigned int) frag_len);
116704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
116804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				dialog->sd_resp_pos, frag_len);
116904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (buf == NULL) {
117004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
117104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			"buffer");
1172b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		gas_serv_dialog_clear(dialog);
1173b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return;
117404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
117504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
117604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt						  WLAN_STATUS_SUCCESS,
117704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt						  dialog->sd_frag_id,
117804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt						  more, 0, buf);
117904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpabuf_free(buf);
1180b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	if (tx_buf == NULL) {
1181b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		gas_serv_dialog_clear(dialog);
1182b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return;
1183b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	}
118404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
118504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		"(frag_id %d more=%d frag_len=%d)",
118604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		dialog->sd_frag_id, more, (int) frag_len);
118704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	dialog->sd_frag_id++;
118804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	dialog->sd_resp_pos += frag_len;
118904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
119004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (more) {
119104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain "
119204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			"to be sent",
119304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			(int) (wpabuf_len(dialog->sd_resp) -
119404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			       dialog->sd_resp_pos));
119504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	} else {
119604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
119704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			"SD response sent");
119804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		gas_serv_dialog_clear(dialog);
119904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		gas_serv_free_dialogs(hapd, sa);
120004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
120104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
120204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtsend_resp:
12031846323989242844f0e857458a8939fa5836429cDmitry Shmidt	if (prot)
12041846323989242844f0e857458a8939fa5836429cDmitry Shmidt		convert_to_protected_dual(tx_buf);
120504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
120604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
120704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpabuf_free(tx_buf);
120804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
120904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
121004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
121104949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
121204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				      int freq)
121304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
121404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct hostapd_data *hapd = ctx;
121504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	const struct ieee80211_mgmt *mgmt;
121604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	const u8 *sa, *data;
12171846323989242844f0e857458a8939fa5836429cDmitry Shmidt	int prot;
121804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
121904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	mgmt = (const struct ieee80211_mgmt *) buf;
1220623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt	if (len < IEEE80211_HDRLEN + 2)
122104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return;
12221846323989242844f0e857458a8939fa5836429cDmitry Shmidt	if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
12231846323989242844f0e857458a8939fa5836429cDmitry Shmidt	    mgmt->u.action.category != WLAN_ACTION_PROTECTED_DUAL)
122404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return;
12251846323989242844f0e857458a8939fa5836429cDmitry Shmidt	/*
12261846323989242844f0e857458a8939fa5836429cDmitry Shmidt	 * Note: Public Action and Protected Dual of Public Action frames share
12271846323989242844f0e857458a8939fa5836429cDmitry Shmidt	 * the same payload structure, so it is fine to use definitions of
12281846323989242844f0e857458a8939fa5836429cDmitry Shmidt	 * Public Action frames to process both.
12291846323989242844f0e857458a8939fa5836429cDmitry Shmidt	 */
12301846323989242844f0e857458a8939fa5836429cDmitry Shmidt	prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
123104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	sa = mgmt->sa;
1232623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt	len -= IEEE80211_HDRLEN + 1;
1233623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt	data = buf + IEEE80211_HDRLEN + 1;
123404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	switch (data[0]) {
123504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	case WLAN_PA_GAS_INITIAL_REQ:
12361846323989242844f0e857458a8939fa5836429cDmitry Shmidt		gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot);
123704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		break;
123804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	case WLAN_PA_GAS_COMEBACK_REQ:
12391846323989242844f0e857458a8939fa5836429cDmitry Shmidt		gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot);
124004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		break;
124104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
124204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
124304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
124404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
124504949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint gas_serv_init(struct hostapd_data *hapd)
124604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
12474b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	hapd->public_action_cb2 = gas_serv_rx_public_action;
12484b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	hapd->public_action_cb2_ctx = hapd;
124904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	hapd->gas_frag_limit = 1400;
125004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (hapd->conf->gas_frag_limit > 0)
125104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
125204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return 0;
125304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
125404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
125504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
125604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtvoid gas_serv_deinit(struct hostapd_data *hapd)
125704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
125804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
1259