1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * Generic advertisement service (GAS) server
3e5b75505Sopenharmony_ci * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci */
8e5b75505Sopenharmony_ci
9e5b75505Sopenharmony_ci#include "includes.h"
10e5b75505Sopenharmony_ci
11e5b75505Sopenharmony_ci#include "common.h"
12e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h"
13e5b75505Sopenharmony_ci#include "common/gas.h"
14e5b75505Sopenharmony_ci#include "common/wpa_ctrl.h"
15e5b75505Sopenharmony_ci#include "utils/eloop.h"
16e5b75505Sopenharmony_ci#include "hostapd.h"
17e5b75505Sopenharmony_ci#include "ap_config.h"
18e5b75505Sopenharmony_ci#include "ap_drv_ops.h"
19e5b75505Sopenharmony_ci#include "dpp_hostapd.h"
20e5b75505Sopenharmony_ci#include "sta_info.h"
21e5b75505Sopenharmony_ci#include "gas_serv.h"
22e5b75505Sopenharmony_ci
23e5b75505Sopenharmony_ci
24e5b75505Sopenharmony_ci#ifdef CONFIG_DPP
25e5b75505Sopenharmony_cistatic void gas_serv_write_dpp_adv_proto(struct wpabuf *buf)
26e5b75505Sopenharmony_ci{
27e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
28e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 8); /* Length */
29e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 0x7f);
30e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
31e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 5);
32e5b75505Sopenharmony_ci	wpabuf_put_be24(buf, OUI_WFA);
33e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, DPP_OUI_TYPE);
34e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 0x01);
35e5b75505Sopenharmony_ci}
36e5b75505Sopenharmony_ci#endif /* CONFIG_DPP */
37e5b75505Sopenharmony_ci
38e5b75505Sopenharmony_ci
39e5b75505Sopenharmony_cistatic void convert_to_protected_dual(struct wpabuf *msg)
40e5b75505Sopenharmony_ci{
41e5b75505Sopenharmony_ci	u8 *categ = wpabuf_mhead_u8(msg);
42e5b75505Sopenharmony_ci	*categ = WLAN_ACTION_PROTECTED_DUAL;
43e5b75505Sopenharmony_ci}
44e5b75505Sopenharmony_ci
45e5b75505Sopenharmony_ci
46e5b75505Sopenharmony_cistatic struct gas_dialog_info *
47e5b75505Sopenharmony_cigas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
48e5b75505Sopenharmony_ci{
49e5b75505Sopenharmony_ci	struct sta_info *sta;
50e5b75505Sopenharmony_ci	struct gas_dialog_info *dia = NULL;
51e5b75505Sopenharmony_ci	int i, j;
52e5b75505Sopenharmony_ci
53e5b75505Sopenharmony_ci	sta = ap_get_sta(hapd, addr);
54e5b75505Sopenharmony_ci	if (!sta) {
55e5b75505Sopenharmony_ci		/*
56e5b75505Sopenharmony_ci		 * We need a STA entry to be able to maintain state for
57e5b75505Sopenharmony_ci		 * the GAS query.
58e5b75505Sopenharmony_ci		 */
59e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for "
60e5b75505Sopenharmony_ci			   "GAS query");
61e5b75505Sopenharmony_ci		sta = ap_sta_add(hapd, addr);
62e5b75505Sopenharmony_ci		if (!sta) {
63e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR
64e5b75505Sopenharmony_ci				   " for GAS query", MAC2STR(addr));
65e5b75505Sopenharmony_ci			return NULL;
66e5b75505Sopenharmony_ci		}
67e5b75505Sopenharmony_ci		sta->flags |= WLAN_STA_GAS;
68e5b75505Sopenharmony_ci		/*
69e5b75505Sopenharmony_ci		 * The default inactivity is 300 seconds. We don't need
70e5b75505Sopenharmony_ci		 * it to be that long. Use five second timeout and increase this
71e5b75505Sopenharmony_ci		 * with the comeback_delay for testing cases.
72e5b75505Sopenharmony_ci		 */
73e5b75505Sopenharmony_ci		ap_sta_session_timeout(hapd, sta,
74e5b75505Sopenharmony_ci				       hapd->conf->gas_comeback_delay / 1024 +
75e5b75505Sopenharmony_ci				       5);
76e5b75505Sopenharmony_ci	} else {
77e5b75505Sopenharmony_ci		ap_sta_replenish_timeout(hapd, sta, 5);
78e5b75505Sopenharmony_ci	}
79e5b75505Sopenharmony_ci
80e5b75505Sopenharmony_ci	if (sta->gas_dialog == NULL) {
81e5b75505Sopenharmony_ci		sta->gas_dialog = os_calloc(GAS_DIALOG_MAX,
82e5b75505Sopenharmony_ci					    sizeof(struct gas_dialog_info));
83e5b75505Sopenharmony_ci		if (sta->gas_dialog == NULL)
84e5b75505Sopenharmony_ci			return NULL;
85e5b75505Sopenharmony_ci	}
86e5b75505Sopenharmony_ci
87e5b75505Sopenharmony_ci	for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) {
88e5b75505Sopenharmony_ci		if (i == GAS_DIALOG_MAX)
89e5b75505Sopenharmony_ci			i = 0;
90e5b75505Sopenharmony_ci		if (sta->gas_dialog[i].valid)
91e5b75505Sopenharmony_ci			continue;
92e5b75505Sopenharmony_ci		dia = &sta->gas_dialog[i];
93e5b75505Sopenharmony_ci		dia->valid = 1;
94e5b75505Sopenharmony_ci		dia->dialog_token = dialog_token;
95e5b75505Sopenharmony_ci		sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i;
96e5b75505Sopenharmony_ci		return dia;
97e5b75505Sopenharmony_ci	}
98e5b75505Sopenharmony_ci
99e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_ERROR, "ANQP: Could not create dialog for "
100e5b75505Sopenharmony_ci		MACSTR " dialog_token %u. Consider increasing "
101e5b75505Sopenharmony_ci		"GAS_DIALOG_MAX.", MAC2STR(addr), dialog_token);
102e5b75505Sopenharmony_ci
103e5b75505Sopenharmony_ci	return NULL;
104e5b75505Sopenharmony_ci}
105e5b75505Sopenharmony_ci
106e5b75505Sopenharmony_ci
107e5b75505Sopenharmony_cistruct gas_dialog_info *
108e5b75505Sopenharmony_cigas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
109e5b75505Sopenharmony_ci		     u8 dialog_token)
110e5b75505Sopenharmony_ci{
111e5b75505Sopenharmony_ci	struct sta_info *sta;
112e5b75505Sopenharmony_ci	int i;
113e5b75505Sopenharmony_ci
114e5b75505Sopenharmony_ci	sta = ap_get_sta(hapd, addr);
115e5b75505Sopenharmony_ci	if (!sta) {
116e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR,
117e5b75505Sopenharmony_ci			   MAC2STR(addr));
118e5b75505Sopenharmony_ci		return NULL;
119e5b75505Sopenharmony_ci	}
120e5b75505Sopenharmony_ci	for (i = 0; sta->gas_dialog && i < GAS_DIALOG_MAX; i++) {
121e5b75505Sopenharmony_ci		if (sta->gas_dialog[i].dialog_token != dialog_token ||
122e5b75505Sopenharmony_ci		    !sta->gas_dialog[i].valid)
123e5b75505Sopenharmony_ci			continue;
124e5b75505Sopenharmony_ci		ap_sta_replenish_timeout(hapd, sta, 5);
125e5b75505Sopenharmony_ci		return &sta->gas_dialog[i];
126e5b75505Sopenharmony_ci	}
127e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
128e5b75505Sopenharmony_ci		   MACSTR " dialog_token %u", MAC2STR(addr), dialog_token);
129e5b75505Sopenharmony_ci	return NULL;
130e5b75505Sopenharmony_ci}
131e5b75505Sopenharmony_ci
132e5b75505Sopenharmony_ci
133e5b75505Sopenharmony_civoid gas_serv_dialog_clear(struct gas_dialog_info *dia)
134e5b75505Sopenharmony_ci{
135e5b75505Sopenharmony_ci	wpabuf_free(dia->sd_resp);
136e5b75505Sopenharmony_ci	os_memset(dia, 0, sizeof(*dia));
137e5b75505Sopenharmony_ci}
138e5b75505Sopenharmony_ci
139e5b75505Sopenharmony_ci
140e5b75505Sopenharmony_cistatic void gas_serv_free_dialogs(struct hostapd_data *hapd,
141e5b75505Sopenharmony_ci				  const u8 *sta_addr)
142e5b75505Sopenharmony_ci{
143e5b75505Sopenharmony_ci	struct sta_info *sta;
144e5b75505Sopenharmony_ci	int i;
145e5b75505Sopenharmony_ci
146e5b75505Sopenharmony_ci	sta = ap_get_sta(hapd, sta_addr);
147e5b75505Sopenharmony_ci	if (sta == NULL || sta->gas_dialog == NULL)
148e5b75505Sopenharmony_ci		return;
149e5b75505Sopenharmony_ci
150e5b75505Sopenharmony_ci	for (i = 0; i < GAS_DIALOG_MAX; i++) {
151e5b75505Sopenharmony_ci		if (sta->gas_dialog[i].valid)
152e5b75505Sopenharmony_ci			return;
153e5b75505Sopenharmony_ci	}
154e5b75505Sopenharmony_ci
155e5b75505Sopenharmony_ci	os_free(sta->gas_dialog);
156e5b75505Sopenharmony_ci	sta->gas_dialog = NULL;
157e5b75505Sopenharmony_ci}
158e5b75505Sopenharmony_ci
159e5b75505Sopenharmony_ci
160e5b75505Sopenharmony_ci#ifdef CONFIG_HS20
161e5b75505Sopenharmony_cistatic void anqp_add_hs_capab_list(struct hostapd_data *hapd,
162e5b75505Sopenharmony_ci				   struct wpabuf *buf)
163e5b75505Sopenharmony_ci{
164e5b75505Sopenharmony_ci	u8 *len;
165e5b75505Sopenharmony_ci
166e5b75505Sopenharmony_ci	len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
167e5b75505Sopenharmony_ci	wpabuf_put_be24(buf, OUI_WFA);
168e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
169e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
170e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 0); /* Reserved */
171e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
172e5b75505Sopenharmony_ci	if (hapd->conf->hs20_oper_friendly_name)
173e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
174e5b75505Sopenharmony_ci	if (hapd->conf->hs20_wan_metrics)
175e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
176e5b75505Sopenharmony_ci	if (hapd->conf->hs20_connection_capability)
177e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
178e5b75505Sopenharmony_ci	if (hapd->conf->nai_realm_data)
179e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
180e5b75505Sopenharmony_ci	if (hapd->conf->hs20_operating_class)
181e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
182e5b75505Sopenharmony_ci	if (hapd->conf->hs20_osu_providers_count)
183e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
184e5b75505Sopenharmony_ci	if (hapd->conf->hs20_osu_providers_nai_count)
185e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
186e5b75505Sopenharmony_ci	if (hapd->conf->hs20_icons_count)
187e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
188e5b75505Sopenharmony_ci	if (hapd->conf->hs20_operator_icon_count)
189e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
190e5b75505Sopenharmony_ci	gas_anqp_set_element_len(buf, len);
191e5b75505Sopenharmony_ci}
192e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */
193e5b75505Sopenharmony_ci
194e5b75505Sopenharmony_ci
195e5b75505Sopenharmony_cistatic struct anqp_element * get_anqp_elem(struct hostapd_data *hapd,
196e5b75505Sopenharmony_ci					   u16 infoid)
197e5b75505Sopenharmony_ci{
198e5b75505Sopenharmony_ci	struct anqp_element *elem;
199e5b75505Sopenharmony_ci
200e5b75505Sopenharmony_ci	dl_list_for_each(elem, &hapd->conf->anqp_elem, struct anqp_element,
201e5b75505Sopenharmony_ci			 list) {
202e5b75505Sopenharmony_ci		if (elem->infoid == infoid)
203e5b75505Sopenharmony_ci			return elem;
204e5b75505Sopenharmony_ci	}
205e5b75505Sopenharmony_ci
206e5b75505Sopenharmony_ci	return NULL;
207e5b75505Sopenharmony_ci}
208e5b75505Sopenharmony_ci
209e5b75505Sopenharmony_ci
210e5b75505Sopenharmony_cistatic void anqp_add_elem(struct hostapd_data *hapd, struct wpabuf *buf,
211e5b75505Sopenharmony_ci			  u16 infoid)
212e5b75505Sopenharmony_ci{
213e5b75505Sopenharmony_ci	struct anqp_element *elem;
214e5b75505Sopenharmony_ci
215e5b75505Sopenharmony_ci	elem = get_anqp_elem(hapd, infoid);
216e5b75505Sopenharmony_ci	if (!elem)
217e5b75505Sopenharmony_ci		return;
218e5b75505Sopenharmony_ci	if (wpabuf_tailroom(buf) < 2 + 2 + wpabuf_len(elem->payload)) {
219e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: No room for InfoID %u payload",
220e5b75505Sopenharmony_ci			   infoid);
221e5b75505Sopenharmony_ci		return;
222e5b75505Sopenharmony_ci	}
223e5b75505Sopenharmony_ci
224e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, infoid);
225e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, wpabuf_len(elem->payload));
226e5b75505Sopenharmony_ci	wpabuf_put_buf(buf, elem->payload);
227e5b75505Sopenharmony_ci}
228e5b75505Sopenharmony_ci
229e5b75505Sopenharmony_ci
230e5b75505Sopenharmony_cistatic int anqp_add_override(struct hostapd_data *hapd, struct wpabuf *buf,
231e5b75505Sopenharmony_ci			     u16 infoid)
232e5b75505Sopenharmony_ci{
233e5b75505Sopenharmony_ci	if (get_anqp_elem(hapd, infoid)) {
234e5b75505Sopenharmony_ci		anqp_add_elem(hapd, buf, infoid);
235e5b75505Sopenharmony_ci		return 1;
236e5b75505Sopenharmony_ci	}
237e5b75505Sopenharmony_ci
238e5b75505Sopenharmony_ci	return 0;
239e5b75505Sopenharmony_ci}
240e5b75505Sopenharmony_ci
241e5b75505Sopenharmony_ci
242e5b75505Sopenharmony_cistatic void anqp_add_capab_list(struct hostapd_data *hapd,
243e5b75505Sopenharmony_ci				struct wpabuf *buf)
244e5b75505Sopenharmony_ci{
245e5b75505Sopenharmony_ci	u8 *len;
246e5b75505Sopenharmony_ci	u16 id;
247e5b75505Sopenharmony_ci
248e5b75505Sopenharmony_ci	if (anqp_add_override(hapd, buf, ANQP_CAPABILITY_LIST))
249e5b75505Sopenharmony_ci		return;
250e5b75505Sopenharmony_ci
251e5b75505Sopenharmony_ci	len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
252e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
253e5b75505Sopenharmony_ci	if (hapd->conf->venue_name || get_anqp_elem(hapd, ANQP_VENUE_NAME))
254e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_VENUE_NAME);
255e5b75505Sopenharmony_ci	if (get_anqp_elem(hapd, ANQP_EMERGENCY_CALL_NUMBER))
256e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_EMERGENCY_CALL_NUMBER);
257e5b75505Sopenharmony_ci	if (hapd->conf->network_auth_type ||
258e5b75505Sopenharmony_ci	    get_anqp_elem(hapd, ANQP_NETWORK_AUTH_TYPE))
259e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
260e5b75505Sopenharmony_ci	if (hapd->conf->roaming_consortium ||
261e5b75505Sopenharmony_ci	    get_anqp_elem(hapd, ANQP_ROAMING_CONSORTIUM))
262e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
263e5b75505Sopenharmony_ci	if (hapd->conf->ipaddr_type_configured ||
264e5b75505Sopenharmony_ci	    get_anqp_elem(hapd, ANQP_IP_ADDR_TYPE_AVAILABILITY))
265e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
266e5b75505Sopenharmony_ci	if (hapd->conf->nai_realm_data ||
267e5b75505Sopenharmony_ci	    get_anqp_elem(hapd, ANQP_NAI_REALM))
268e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_NAI_REALM);
269e5b75505Sopenharmony_ci	if (hapd->conf->anqp_3gpp_cell_net ||
270e5b75505Sopenharmony_ci	    get_anqp_elem(hapd, ANQP_3GPP_CELLULAR_NETWORK))
271e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
272e5b75505Sopenharmony_ci	if (get_anqp_elem(hapd, ANQP_AP_GEOSPATIAL_LOCATION))
273e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_AP_GEOSPATIAL_LOCATION);
274e5b75505Sopenharmony_ci	if (get_anqp_elem(hapd, ANQP_AP_CIVIC_LOCATION))
275e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_AP_CIVIC_LOCATION);
276e5b75505Sopenharmony_ci	if (get_anqp_elem(hapd, ANQP_AP_LOCATION_PUBLIC_URI))
277e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_AP_LOCATION_PUBLIC_URI);
278e5b75505Sopenharmony_ci	if (hapd->conf->domain_name || get_anqp_elem(hapd, ANQP_DOMAIN_NAME))
279e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
280e5b75505Sopenharmony_ci	if (get_anqp_elem(hapd, ANQP_EMERGENCY_ALERT_URI))
281e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_EMERGENCY_ALERT_URI);
282e5b75505Sopenharmony_ci	if (get_anqp_elem(hapd, ANQP_TDLS_CAPABILITY))
283e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_TDLS_CAPABILITY);
284e5b75505Sopenharmony_ci	if (get_anqp_elem(hapd, ANQP_EMERGENCY_NAI))
285e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_EMERGENCY_NAI);
286e5b75505Sopenharmony_ci	if (get_anqp_elem(hapd, ANQP_NEIGHBOR_REPORT))
287e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_NEIGHBOR_REPORT);
288e5b75505Sopenharmony_ci#ifdef CONFIG_FILS
289e5b75505Sopenharmony_ci	if (!dl_list_empty(&hapd->conf->fils_realms) ||
290e5b75505Sopenharmony_ci	    get_anqp_elem(hapd, ANQP_FILS_REALM_INFO))
291e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_FILS_REALM_INFO);
292e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */
293e5b75505Sopenharmony_ci	if (get_anqp_elem(hapd, ANQP_CAG))
294e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_CAG);
295e5b75505Sopenharmony_ci	if (hapd->conf->venue_url || get_anqp_elem(hapd, ANQP_VENUE_URL))
296e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_VENUE_URL);
297e5b75505Sopenharmony_ci	if (get_anqp_elem(hapd, ANQP_ADVICE_OF_CHARGE))
298e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_ADVICE_OF_CHARGE);
299e5b75505Sopenharmony_ci	if (get_anqp_elem(hapd, ANQP_LOCAL_CONTENT))
300e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_LOCAL_CONTENT);
301e5b75505Sopenharmony_ci	for (id = 280; id < 300; id++) {
302e5b75505Sopenharmony_ci		if (get_anqp_elem(hapd, id))
303e5b75505Sopenharmony_ci			wpabuf_put_le16(buf, id);
304e5b75505Sopenharmony_ci	}
305e5b75505Sopenharmony_ci#ifdef CONFIG_HS20
306e5b75505Sopenharmony_ci	anqp_add_hs_capab_list(hapd, buf);
307e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */
308e5b75505Sopenharmony_ci	gas_anqp_set_element_len(buf, len);
309e5b75505Sopenharmony_ci}
310e5b75505Sopenharmony_ci
311e5b75505Sopenharmony_ci
312e5b75505Sopenharmony_cistatic void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
313e5b75505Sopenharmony_ci{
314e5b75505Sopenharmony_ci	if (anqp_add_override(hapd, buf, ANQP_VENUE_NAME))
315e5b75505Sopenharmony_ci		return;
316e5b75505Sopenharmony_ci
317e5b75505Sopenharmony_ci	if (hapd->conf->venue_name) {
318e5b75505Sopenharmony_ci		u8 *len;
319e5b75505Sopenharmony_ci		unsigned int i;
320e5b75505Sopenharmony_ci		len = gas_anqp_add_element(buf, ANQP_VENUE_NAME);
321e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, hapd->conf->venue_group);
322e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, hapd->conf->venue_type);
323e5b75505Sopenharmony_ci		for (i = 0; i < hapd->conf->venue_name_count; i++) {
324e5b75505Sopenharmony_ci			struct hostapd_lang_string *vn;
325e5b75505Sopenharmony_ci			vn = &hapd->conf->venue_name[i];
326e5b75505Sopenharmony_ci			wpabuf_put_u8(buf, 3 + vn->name_len);
327e5b75505Sopenharmony_ci			wpabuf_put_data(buf, vn->lang, 3);
328e5b75505Sopenharmony_ci			wpabuf_put_data(buf, vn->name, vn->name_len);
329e5b75505Sopenharmony_ci		}
330e5b75505Sopenharmony_ci		gas_anqp_set_element_len(buf, len);
331e5b75505Sopenharmony_ci	}
332e5b75505Sopenharmony_ci}
333e5b75505Sopenharmony_ci
334e5b75505Sopenharmony_ci
335e5b75505Sopenharmony_cistatic void anqp_add_venue_url(struct hostapd_data *hapd, struct wpabuf *buf)
336e5b75505Sopenharmony_ci{
337e5b75505Sopenharmony_ci	if (anqp_add_override(hapd, buf, ANQP_VENUE_URL))
338e5b75505Sopenharmony_ci		return;
339e5b75505Sopenharmony_ci
340e5b75505Sopenharmony_ci	if (hapd->conf->venue_url) {
341e5b75505Sopenharmony_ci		u8 *len;
342e5b75505Sopenharmony_ci		unsigned int i;
343e5b75505Sopenharmony_ci
344e5b75505Sopenharmony_ci		len = gas_anqp_add_element(buf, ANQP_VENUE_URL);
345e5b75505Sopenharmony_ci		for (i = 0; i < hapd->conf->venue_url_count; i++) {
346e5b75505Sopenharmony_ci			struct hostapd_venue_url *url;
347e5b75505Sopenharmony_ci
348e5b75505Sopenharmony_ci			url = &hapd->conf->venue_url[i];
349e5b75505Sopenharmony_ci			wpabuf_put_u8(buf, 1 + url->url_len);
350e5b75505Sopenharmony_ci			wpabuf_put_u8(buf, url->venue_number);
351e5b75505Sopenharmony_ci			wpabuf_put_data(buf, url->url, url->url_len);
352e5b75505Sopenharmony_ci		}
353e5b75505Sopenharmony_ci		gas_anqp_set_element_len(buf, len);
354e5b75505Sopenharmony_ci	}
355e5b75505Sopenharmony_ci}
356e5b75505Sopenharmony_ci
357e5b75505Sopenharmony_ci
358e5b75505Sopenharmony_cistatic void anqp_add_network_auth_type(struct hostapd_data *hapd,
359e5b75505Sopenharmony_ci				       struct wpabuf *buf)
360e5b75505Sopenharmony_ci{
361e5b75505Sopenharmony_ci	if (anqp_add_override(hapd, buf, ANQP_NETWORK_AUTH_TYPE))
362e5b75505Sopenharmony_ci		return;
363e5b75505Sopenharmony_ci
364e5b75505Sopenharmony_ci	if (hapd->conf->network_auth_type) {
365e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
366e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
367e5b75505Sopenharmony_ci		wpabuf_put_data(buf, hapd->conf->network_auth_type,
368e5b75505Sopenharmony_ci				hapd->conf->network_auth_type_len);
369e5b75505Sopenharmony_ci	}
370e5b75505Sopenharmony_ci}
371e5b75505Sopenharmony_ci
372e5b75505Sopenharmony_ci
373e5b75505Sopenharmony_cistatic void anqp_add_roaming_consortium(struct hostapd_data *hapd,
374e5b75505Sopenharmony_ci					struct wpabuf *buf)
375e5b75505Sopenharmony_ci{
376e5b75505Sopenharmony_ci	unsigned int i;
377e5b75505Sopenharmony_ci	u8 *len;
378e5b75505Sopenharmony_ci
379e5b75505Sopenharmony_ci	if (anqp_add_override(hapd, buf, ANQP_ROAMING_CONSORTIUM))
380e5b75505Sopenharmony_ci		return;
381e5b75505Sopenharmony_ci
382e5b75505Sopenharmony_ci	len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
383e5b75505Sopenharmony_ci	for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
384e5b75505Sopenharmony_ci		struct hostapd_roaming_consortium *rc;
385e5b75505Sopenharmony_ci		rc = &hapd->conf->roaming_consortium[i];
386e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, rc->len);
387e5b75505Sopenharmony_ci		wpabuf_put_data(buf, rc->oi, rc->len);
388e5b75505Sopenharmony_ci	}
389e5b75505Sopenharmony_ci	gas_anqp_set_element_len(buf, len);
390e5b75505Sopenharmony_ci}
391e5b75505Sopenharmony_ci
392e5b75505Sopenharmony_ci
393e5b75505Sopenharmony_cistatic void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
394e5b75505Sopenharmony_ci					       struct wpabuf *buf)
395e5b75505Sopenharmony_ci{
396e5b75505Sopenharmony_ci	if (anqp_add_override(hapd, buf, ANQP_IP_ADDR_TYPE_AVAILABILITY))
397e5b75505Sopenharmony_ci		return;
398e5b75505Sopenharmony_ci
399e5b75505Sopenharmony_ci	if (hapd->conf->ipaddr_type_configured) {
400e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
401e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, 1);
402e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, hapd->conf->ipaddr_type_availability);
403e5b75505Sopenharmony_ci	}
404e5b75505Sopenharmony_ci}
405e5b75505Sopenharmony_ci
406e5b75505Sopenharmony_ci
407e5b75505Sopenharmony_cistatic void anqp_add_nai_realm_eap(struct wpabuf *buf,
408e5b75505Sopenharmony_ci				   struct hostapd_nai_realm_data *realm)
409e5b75505Sopenharmony_ci{
410e5b75505Sopenharmony_ci	unsigned int i, j;
411e5b75505Sopenharmony_ci
412e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, realm->eap_method_count);
413e5b75505Sopenharmony_ci
414e5b75505Sopenharmony_ci	for (i = 0; i < realm->eap_method_count; i++) {
415e5b75505Sopenharmony_ci		struct hostapd_nai_realm_eap *eap = &realm->eap_method[i];
416e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 2 + (3 * eap->num_auths));
417e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, eap->eap_method);
418e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, eap->num_auths);
419e5b75505Sopenharmony_ci		for (j = 0; j < eap->num_auths; j++) {
420e5b75505Sopenharmony_ci			wpabuf_put_u8(buf, eap->auth_id[j]);
421e5b75505Sopenharmony_ci			wpabuf_put_u8(buf, 1);
422e5b75505Sopenharmony_ci			wpabuf_put_u8(buf, eap->auth_val[j]);
423e5b75505Sopenharmony_ci		}
424e5b75505Sopenharmony_ci	}
425e5b75505Sopenharmony_ci}
426e5b75505Sopenharmony_ci
427e5b75505Sopenharmony_ci
428e5b75505Sopenharmony_cistatic void anqp_add_nai_realm_data(struct wpabuf *buf,
429e5b75505Sopenharmony_ci				    struct hostapd_nai_realm_data *realm,
430e5b75505Sopenharmony_ci				    unsigned int realm_idx)
431e5b75505Sopenharmony_ci{
432e5b75505Sopenharmony_ci	u8 *realm_data_len;
433e5b75505Sopenharmony_ci
434e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx],
435e5b75505Sopenharmony_ci		   (int) os_strlen(realm->realm[realm_idx]));
436e5b75505Sopenharmony_ci	realm_data_len = wpabuf_put(buf, 2);
437e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, realm->encoding);
438e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx]));
439e5b75505Sopenharmony_ci	wpabuf_put_str(buf, realm->realm[realm_idx]);
440e5b75505Sopenharmony_ci	anqp_add_nai_realm_eap(buf, realm);
441e5b75505Sopenharmony_ci	gas_anqp_set_element_len(buf, realm_data_len);
442e5b75505Sopenharmony_ci}
443e5b75505Sopenharmony_ci
444e5b75505Sopenharmony_ci
445e5b75505Sopenharmony_cistatic int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
446e5b75505Sopenharmony_ci					   struct wpabuf *buf,
447e5b75505Sopenharmony_ci					   const u8 *home_realm,
448e5b75505Sopenharmony_ci					   size_t home_realm_len)
449e5b75505Sopenharmony_ci{
450e5b75505Sopenharmony_ci	unsigned int i, j, k;
451e5b75505Sopenharmony_ci	u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len;
452e5b75505Sopenharmony_ci	struct hostapd_nai_realm_data *realm;
453e5b75505Sopenharmony_ci	const u8 *pos, *realm_name, *end;
454e5b75505Sopenharmony_ci	struct {
455e5b75505Sopenharmony_ci		unsigned int realm_data_idx;
456e5b75505Sopenharmony_ci		unsigned int realm_idx;
457e5b75505Sopenharmony_ci	} matches[10];
458e5b75505Sopenharmony_ci
459e5b75505Sopenharmony_ci	pos = home_realm;
460e5b75505Sopenharmony_ci	end = pos + home_realm_len;
461e5b75505Sopenharmony_ci	if (end - pos < 1) {
462e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
463e5b75505Sopenharmony_ci			    home_realm, home_realm_len);
464e5b75505Sopenharmony_ci		return -1;
465e5b75505Sopenharmony_ci	}
466e5b75505Sopenharmony_ci	num_realms = *pos++;
467e5b75505Sopenharmony_ci
468e5b75505Sopenharmony_ci	for (i = 0; i < num_realms && num_matching < 10; i++) {
469e5b75505Sopenharmony_ci		if (end - pos < 2) {
470e5b75505Sopenharmony_ci			wpa_hexdump(MSG_DEBUG,
471e5b75505Sopenharmony_ci				    "Truncated NAI Home Realm Query",
472e5b75505Sopenharmony_ci				    home_realm, home_realm_len);
473e5b75505Sopenharmony_ci			return -1;
474e5b75505Sopenharmony_ci		}
475e5b75505Sopenharmony_ci		encoding = *pos++;
476e5b75505Sopenharmony_ci		realm_len = *pos++;
477e5b75505Sopenharmony_ci		if (realm_len > end - pos) {
478e5b75505Sopenharmony_ci			wpa_hexdump(MSG_DEBUG,
479e5b75505Sopenharmony_ci				    "Truncated NAI Home Realm Query",
480e5b75505Sopenharmony_ci				    home_realm, home_realm_len);
481e5b75505Sopenharmony_ci			return -1;
482e5b75505Sopenharmony_ci		}
483e5b75505Sopenharmony_ci		realm_name = pos;
484e5b75505Sopenharmony_ci		for (j = 0; j < hapd->conf->nai_realm_count &&
485e5b75505Sopenharmony_ci			     num_matching < 10; j++) {
486e5b75505Sopenharmony_ci			const u8 *rpos, *rend;
487e5b75505Sopenharmony_ci			realm = &hapd->conf->nai_realm_data[j];
488e5b75505Sopenharmony_ci			if (encoding != realm->encoding)
489e5b75505Sopenharmony_ci				continue;
490e5b75505Sopenharmony_ci
491e5b75505Sopenharmony_ci			rpos = realm_name;
492e5b75505Sopenharmony_ci			while (rpos < realm_name + realm_len &&
493e5b75505Sopenharmony_ci			       num_matching < 10) {
494e5b75505Sopenharmony_ci				for (rend = rpos;
495e5b75505Sopenharmony_ci				     rend < realm_name + realm_len; rend++) {
496e5b75505Sopenharmony_ci					if (*rend == ';')
497e5b75505Sopenharmony_ci						break;
498e5b75505Sopenharmony_ci				}
499e5b75505Sopenharmony_ci				for (k = 0; k < MAX_NAI_REALMS &&
500e5b75505Sopenharmony_ci					     realm->realm[k] &&
501e5b75505Sopenharmony_ci					     num_matching < 10; k++) {
502e5b75505Sopenharmony_ci					if ((int) os_strlen(realm->realm[k]) !=
503e5b75505Sopenharmony_ci					    rend - rpos ||
504e5b75505Sopenharmony_ci					    os_strncmp((char *) rpos,
505e5b75505Sopenharmony_ci						       realm->realm[k],
506e5b75505Sopenharmony_ci						       rend - rpos) != 0)
507e5b75505Sopenharmony_ci						continue;
508e5b75505Sopenharmony_ci					matches[num_matching].realm_data_idx =
509e5b75505Sopenharmony_ci						j;
510e5b75505Sopenharmony_ci					matches[num_matching].realm_idx = k;
511e5b75505Sopenharmony_ci					num_matching++;
512e5b75505Sopenharmony_ci				}
513e5b75505Sopenharmony_ci				rpos = rend + 1;
514e5b75505Sopenharmony_ci			}
515e5b75505Sopenharmony_ci		}
516e5b75505Sopenharmony_ci		pos += realm_len;
517e5b75505Sopenharmony_ci	}
518e5b75505Sopenharmony_ci
519e5b75505Sopenharmony_ci	realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
520e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, num_matching);
521e5b75505Sopenharmony_ci
522e5b75505Sopenharmony_ci	/*
523e5b75505Sopenharmony_ci	 * There are two ways to format. 1. each realm in a NAI Realm Data unit
524e5b75505Sopenharmony_ci	 * 2. all realms that share the same EAP methods in a NAI Realm Data
525e5b75505Sopenharmony_ci	 * unit. The first format is likely to be bigger in size than the
526e5b75505Sopenharmony_ci	 * second, but may be easier to parse and process by the receiver.
527e5b75505Sopenharmony_ci	 */
528e5b75505Sopenharmony_ci	for (i = 0; i < num_matching; i++) {
529e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d",
530e5b75505Sopenharmony_ci			   matches[i].realm_data_idx, matches[i].realm_idx);
531e5b75505Sopenharmony_ci		realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx];
532e5b75505Sopenharmony_ci		anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx);
533e5b75505Sopenharmony_ci	}
534e5b75505Sopenharmony_ci	gas_anqp_set_element_len(buf, realm_list_len);
535e5b75505Sopenharmony_ci	return 0;
536e5b75505Sopenharmony_ci}
537e5b75505Sopenharmony_ci
538e5b75505Sopenharmony_ci
539e5b75505Sopenharmony_cistatic void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
540e5b75505Sopenharmony_ci			       const u8 *home_realm, size_t home_realm_len,
541e5b75505Sopenharmony_ci			       int nai_realm, int nai_home_realm)
542e5b75505Sopenharmony_ci{
543e5b75505Sopenharmony_ci	if (nai_realm && !nai_home_realm &&
544e5b75505Sopenharmony_ci	    anqp_add_override(hapd, buf, ANQP_NAI_REALM))
545e5b75505Sopenharmony_ci		return;
546e5b75505Sopenharmony_ci
547e5b75505Sopenharmony_ci	if (nai_realm && hapd->conf->nai_realm_data) {
548e5b75505Sopenharmony_ci		u8 *len;
549e5b75505Sopenharmony_ci		unsigned int i, j;
550e5b75505Sopenharmony_ci		len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
551e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, hapd->conf->nai_realm_count);
552e5b75505Sopenharmony_ci		for (i = 0; i < hapd->conf->nai_realm_count; i++) {
553e5b75505Sopenharmony_ci			u8 *realm_data_len, *realm_len;
554e5b75505Sopenharmony_ci			struct hostapd_nai_realm_data *realm;
555e5b75505Sopenharmony_ci
556e5b75505Sopenharmony_ci			realm = &hapd->conf->nai_realm_data[i];
557e5b75505Sopenharmony_ci			realm_data_len = wpabuf_put(buf, 2);
558e5b75505Sopenharmony_ci			wpabuf_put_u8(buf, realm->encoding);
559e5b75505Sopenharmony_ci			realm_len = wpabuf_put(buf, 1);
560e5b75505Sopenharmony_ci			for (j = 0; realm->realm[j]; j++) {
561e5b75505Sopenharmony_ci				if (j > 0)
562e5b75505Sopenharmony_ci					wpabuf_put_u8(buf, ';');
563e5b75505Sopenharmony_ci				wpabuf_put_str(buf, realm->realm[j]);
564e5b75505Sopenharmony_ci			}
565e5b75505Sopenharmony_ci			*realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1;
566e5b75505Sopenharmony_ci			anqp_add_nai_realm_eap(buf, realm);
567e5b75505Sopenharmony_ci			gas_anqp_set_element_len(buf, realm_data_len);
568e5b75505Sopenharmony_ci		}
569e5b75505Sopenharmony_ci		gas_anqp_set_element_len(buf, len);
570e5b75505Sopenharmony_ci	} else if (nai_home_realm && hapd->conf->nai_realm_data && home_realm) {
571e5b75505Sopenharmony_ci		hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
572e5b75505Sopenharmony_ci						home_realm_len);
573e5b75505Sopenharmony_ci	}
574e5b75505Sopenharmony_ci}
575e5b75505Sopenharmony_ci
576e5b75505Sopenharmony_ci
577e5b75505Sopenharmony_cistatic void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
578e5b75505Sopenharmony_ci					   struct wpabuf *buf)
579e5b75505Sopenharmony_ci{
580e5b75505Sopenharmony_ci	if (anqp_add_override(hapd, buf, ANQP_3GPP_CELLULAR_NETWORK))
581e5b75505Sopenharmony_ci		return;
582e5b75505Sopenharmony_ci
583e5b75505Sopenharmony_ci	if (hapd->conf->anqp_3gpp_cell_net) {
584e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
585e5b75505Sopenharmony_ci		wpabuf_put_le16(buf,
586e5b75505Sopenharmony_ci				hapd->conf->anqp_3gpp_cell_net_len);
587e5b75505Sopenharmony_ci		wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net,
588e5b75505Sopenharmony_ci				hapd->conf->anqp_3gpp_cell_net_len);
589e5b75505Sopenharmony_ci	}
590e5b75505Sopenharmony_ci}
591e5b75505Sopenharmony_ci
592e5b75505Sopenharmony_ci
593e5b75505Sopenharmony_cistatic void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
594e5b75505Sopenharmony_ci{
595e5b75505Sopenharmony_ci	if (anqp_add_override(hapd, buf, ANQP_DOMAIN_NAME))
596e5b75505Sopenharmony_ci		return;
597e5b75505Sopenharmony_ci
598e5b75505Sopenharmony_ci	if (hapd->conf->domain_name) {
599e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
600e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, hapd->conf->domain_name_len);
601e5b75505Sopenharmony_ci		wpabuf_put_data(buf, hapd->conf->domain_name,
602e5b75505Sopenharmony_ci				hapd->conf->domain_name_len);
603e5b75505Sopenharmony_ci	}
604e5b75505Sopenharmony_ci}
605e5b75505Sopenharmony_ci
606e5b75505Sopenharmony_ci
607e5b75505Sopenharmony_ci#ifdef CONFIG_FILS
608e5b75505Sopenharmony_cistatic void anqp_add_fils_realm_info(struct hostapd_data *hapd,
609e5b75505Sopenharmony_ci				     struct wpabuf *buf)
610e5b75505Sopenharmony_ci{
611e5b75505Sopenharmony_ci	size_t count;
612e5b75505Sopenharmony_ci
613e5b75505Sopenharmony_ci	if (anqp_add_override(hapd, buf, ANQP_FILS_REALM_INFO))
614e5b75505Sopenharmony_ci		return;
615e5b75505Sopenharmony_ci
616e5b75505Sopenharmony_ci	count = dl_list_len(&hapd->conf->fils_realms);
617e5b75505Sopenharmony_ci	if (count > 10000)
618e5b75505Sopenharmony_ci		count = 10000;
619e5b75505Sopenharmony_ci	if (count) {
620e5b75505Sopenharmony_ci		struct fils_realm *realm;
621e5b75505Sopenharmony_ci
622e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_FILS_REALM_INFO);
623e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, 2 * count);
624e5b75505Sopenharmony_ci
625e5b75505Sopenharmony_ci		dl_list_for_each(realm, &hapd->conf->fils_realms,
626e5b75505Sopenharmony_ci				 struct fils_realm, list) {
627e5b75505Sopenharmony_ci			if (count == 0)
628e5b75505Sopenharmony_ci				break;
629e5b75505Sopenharmony_ci			wpabuf_put_data(buf, realm->hash, 2);
630e5b75505Sopenharmony_ci			count--;
631e5b75505Sopenharmony_ci		}
632e5b75505Sopenharmony_ci	}
633e5b75505Sopenharmony_ci}
634e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */
635e5b75505Sopenharmony_ci
636e5b75505Sopenharmony_ci
637e5b75505Sopenharmony_ci#ifdef CONFIG_HS20
638e5b75505Sopenharmony_ci
639e5b75505Sopenharmony_cistatic void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
640e5b75505Sopenharmony_ci					    struct wpabuf *buf)
641e5b75505Sopenharmony_ci{
642e5b75505Sopenharmony_ci	if (hapd->conf->hs20_oper_friendly_name) {
643e5b75505Sopenharmony_ci		u8 *len;
644e5b75505Sopenharmony_ci		unsigned int i;
645e5b75505Sopenharmony_ci		len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
646e5b75505Sopenharmony_ci		wpabuf_put_be24(buf, OUI_WFA);
647e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
648e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
649e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 0); /* Reserved */
650e5b75505Sopenharmony_ci		for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++)
651e5b75505Sopenharmony_ci		{
652e5b75505Sopenharmony_ci			struct hostapd_lang_string *vn;
653e5b75505Sopenharmony_ci			vn = &hapd->conf->hs20_oper_friendly_name[i];
654e5b75505Sopenharmony_ci			wpabuf_put_u8(buf, 3 + vn->name_len);
655e5b75505Sopenharmony_ci			wpabuf_put_data(buf, vn->lang, 3);
656e5b75505Sopenharmony_ci			wpabuf_put_data(buf, vn->name, vn->name_len);
657e5b75505Sopenharmony_ci		}
658e5b75505Sopenharmony_ci		gas_anqp_set_element_len(buf, len);
659e5b75505Sopenharmony_ci	}
660e5b75505Sopenharmony_ci}
661e5b75505Sopenharmony_ci
662e5b75505Sopenharmony_ci
663e5b75505Sopenharmony_cistatic void anqp_add_wan_metrics(struct hostapd_data *hapd,
664e5b75505Sopenharmony_ci				 struct wpabuf *buf)
665e5b75505Sopenharmony_ci{
666e5b75505Sopenharmony_ci	if (hapd->conf->hs20_wan_metrics) {
667e5b75505Sopenharmony_ci		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
668e5b75505Sopenharmony_ci		wpabuf_put_be24(buf, OUI_WFA);
669e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
670e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
671e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 0); /* Reserved */
672e5b75505Sopenharmony_ci		wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13);
673e5b75505Sopenharmony_ci		gas_anqp_set_element_len(buf, len);
674e5b75505Sopenharmony_ci	}
675e5b75505Sopenharmony_ci}
676e5b75505Sopenharmony_ci
677e5b75505Sopenharmony_ci
678e5b75505Sopenharmony_cistatic void anqp_add_connection_capability(struct hostapd_data *hapd,
679e5b75505Sopenharmony_ci					   struct wpabuf *buf)
680e5b75505Sopenharmony_ci{
681e5b75505Sopenharmony_ci	if (hapd->conf->hs20_connection_capability) {
682e5b75505Sopenharmony_ci		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
683e5b75505Sopenharmony_ci		wpabuf_put_be24(buf, OUI_WFA);
684e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
685e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
686e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 0); /* Reserved */
687e5b75505Sopenharmony_ci		wpabuf_put_data(buf, hapd->conf->hs20_connection_capability,
688e5b75505Sopenharmony_ci				hapd->conf->hs20_connection_capability_len);
689e5b75505Sopenharmony_ci		gas_anqp_set_element_len(buf, len);
690e5b75505Sopenharmony_ci	}
691e5b75505Sopenharmony_ci}
692e5b75505Sopenharmony_ci
693e5b75505Sopenharmony_ci
694e5b75505Sopenharmony_cistatic void anqp_add_operating_class(struct hostapd_data *hapd,
695e5b75505Sopenharmony_ci				     struct wpabuf *buf)
696e5b75505Sopenharmony_ci{
697e5b75505Sopenharmony_ci	if (hapd->conf->hs20_operating_class) {
698e5b75505Sopenharmony_ci		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
699e5b75505Sopenharmony_ci		wpabuf_put_be24(buf, OUI_WFA);
700e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
701e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
702e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 0); /* Reserved */
703e5b75505Sopenharmony_ci		wpabuf_put_data(buf, hapd->conf->hs20_operating_class,
704e5b75505Sopenharmony_ci				hapd->conf->hs20_operating_class_len);
705e5b75505Sopenharmony_ci		gas_anqp_set_element_len(buf, len);
706e5b75505Sopenharmony_ci	}
707e5b75505Sopenharmony_ci}
708e5b75505Sopenharmony_ci
709e5b75505Sopenharmony_ci
710e5b75505Sopenharmony_cistatic void anqp_add_icon(struct wpabuf *buf, struct hostapd_bss_config *bss,
711e5b75505Sopenharmony_ci			  const char *name)
712e5b75505Sopenharmony_ci{
713e5b75505Sopenharmony_ci	size_t j;
714e5b75505Sopenharmony_ci	struct hs20_icon *icon = NULL;
715e5b75505Sopenharmony_ci
716e5b75505Sopenharmony_ci	for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
717e5b75505Sopenharmony_ci		if (os_strcmp(name, bss->hs20_icons[j].name) == 0)
718e5b75505Sopenharmony_ci			icon = &bss->hs20_icons[j];
719e5b75505Sopenharmony_ci	}
720e5b75505Sopenharmony_ci	if (!icon)
721e5b75505Sopenharmony_ci		return; /* icon info not found */
722e5b75505Sopenharmony_ci
723e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, icon->width);
724e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, icon->height);
725e5b75505Sopenharmony_ci	wpabuf_put_data(buf, icon->language, 3);
726e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, os_strlen(icon->type));
727e5b75505Sopenharmony_ci	wpabuf_put_str(buf, icon->type);
728e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, os_strlen(icon->name));
729e5b75505Sopenharmony_ci	wpabuf_put_str(buf, icon->name);
730e5b75505Sopenharmony_ci}
731e5b75505Sopenharmony_ci
732e5b75505Sopenharmony_ci
733e5b75505Sopenharmony_cistatic void anqp_add_osu_provider(struct wpabuf *buf,
734e5b75505Sopenharmony_ci				  struct hostapd_bss_config *bss,
735e5b75505Sopenharmony_ci				  struct hs20_osu_provider *p)
736e5b75505Sopenharmony_ci{
737e5b75505Sopenharmony_ci	u8 *len, *len2, *count;
738e5b75505Sopenharmony_ci	unsigned int i;
739e5b75505Sopenharmony_ci
740e5b75505Sopenharmony_ci	len = wpabuf_put(buf, 2); /* OSU Provider Length to be filled */
741e5b75505Sopenharmony_ci
742e5b75505Sopenharmony_ci	/* OSU Friendly Name Duples */
743e5b75505Sopenharmony_ci	len2 = wpabuf_put(buf, 2);
744e5b75505Sopenharmony_ci	for (i = 0; i < p->friendly_name_count; i++) {
745e5b75505Sopenharmony_ci		struct hostapd_lang_string *s = &p->friendly_name[i];
746e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 3 + s->name_len);
747e5b75505Sopenharmony_ci		wpabuf_put_data(buf, s->lang, 3);
748e5b75505Sopenharmony_ci		wpabuf_put_data(buf, s->name, s->name_len);
749e5b75505Sopenharmony_ci	}
750e5b75505Sopenharmony_ci	WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
751e5b75505Sopenharmony_ci
752e5b75505Sopenharmony_ci	/* OSU Server URI */
753e5b75505Sopenharmony_ci	if (p->server_uri) {
754e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, os_strlen(p->server_uri));
755e5b75505Sopenharmony_ci		wpabuf_put_str(buf, p->server_uri);
756e5b75505Sopenharmony_ci	} else
757e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 0);
758e5b75505Sopenharmony_ci
759e5b75505Sopenharmony_ci	/* OSU Method List */
760e5b75505Sopenharmony_ci	count = wpabuf_put(buf, 1);
761e5b75505Sopenharmony_ci	for (i = 0; p->method_list && p->method_list[i] >= 0; i++)
762e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, p->method_list[i]);
763e5b75505Sopenharmony_ci	*count = i;
764e5b75505Sopenharmony_ci
765e5b75505Sopenharmony_ci	/* Icons Available */
766e5b75505Sopenharmony_ci	len2 = wpabuf_put(buf, 2);
767e5b75505Sopenharmony_ci	for (i = 0; i < p->icons_count; i++)
768e5b75505Sopenharmony_ci		anqp_add_icon(buf, bss, p->icons[i]);
769e5b75505Sopenharmony_ci	WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
770e5b75505Sopenharmony_ci
771e5b75505Sopenharmony_ci	/* OSU_NAI */
772e5b75505Sopenharmony_ci	if (p->osu_nai) {
773e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, os_strlen(p->osu_nai));
774e5b75505Sopenharmony_ci		wpabuf_put_str(buf, p->osu_nai);
775e5b75505Sopenharmony_ci	} else
776e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 0);
777e5b75505Sopenharmony_ci
778e5b75505Sopenharmony_ci	/* OSU Service Description Duples */
779e5b75505Sopenharmony_ci	len2 = wpabuf_put(buf, 2);
780e5b75505Sopenharmony_ci	for (i = 0; i < p->service_desc_count; i++) {
781e5b75505Sopenharmony_ci		struct hostapd_lang_string *s = &p->service_desc[i];
782e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 3 + s->name_len);
783e5b75505Sopenharmony_ci		wpabuf_put_data(buf, s->lang, 3);
784e5b75505Sopenharmony_ci		wpabuf_put_data(buf, s->name, s->name_len);
785e5b75505Sopenharmony_ci	}
786e5b75505Sopenharmony_ci	WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
787e5b75505Sopenharmony_ci
788e5b75505Sopenharmony_ci	WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
789e5b75505Sopenharmony_ci}
790e5b75505Sopenharmony_ci
791e5b75505Sopenharmony_ci
792e5b75505Sopenharmony_cistatic void anqp_add_osu_providers_list(struct hostapd_data *hapd,
793e5b75505Sopenharmony_ci					struct wpabuf *buf)
794e5b75505Sopenharmony_ci{
795e5b75505Sopenharmony_ci	if (hapd->conf->hs20_osu_providers_count) {
796e5b75505Sopenharmony_ci		size_t i;
797e5b75505Sopenharmony_ci		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
798e5b75505Sopenharmony_ci		wpabuf_put_be24(buf, OUI_WFA);
799e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
800e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
801e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 0); /* Reserved */
802e5b75505Sopenharmony_ci
803e5b75505Sopenharmony_ci		/* OSU SSID */
804e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, hapd->conf->osu_ssid_len);
805e5b75505Sopenharmony_ci		wpabuf_put_data(buf, hapd->conf->osu_ssid,
806e5b75505Sopenharmony_ci				hapd->conf->osu_ssid_len);
807e5b75505Sopenharmony_ci
808e5b75505Sopenharmony_ci		/* Number of OSU Providers */
809e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, hapd->conf->hs20_osu_providers_count);
810e5b75505Sopenharmony_ci
811e5b75505Sopenharmony_ci		for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
812e5b75505Sopenharmony_ci			anqp_add_osu_provider(
813e5b75505Sopenharmony_ci				buf, hapd->conf,
814e5b75505Sopenharmony_ci				&hapd->conf->hs20_osu_providers[i]);
815e5b75505Sopenharmony_ci		}
816e5b75505Sopenharmony_ci
817e5b75505Sopenharmony_ci		gas_anqp_set_element_len(buf, len);
818e5b75505Sopenharmony_ci	}
819e5b75505Sopenharmony_ci}
820e5b75505Sopenharmony_ci
821e5b75505Sopenharmony_ci
822e5b75505Sopenharmony_cistatic void anqp_add_osu_provider_nai(struct wpabuf *buf,
823e5b75505Sopenharmony_ci				      struct hs20_osu_provider *p)
824e5b75505Sopenharmony_ci{
825e5b75505Sopenharmony_ci	/* OSU_NAI for shared BSS (Single SSID) */
826e5b75505Sopenharmony_ci	if (p->osu_nai2) {
827e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, os_strlen(p->osu_nai2));
828e5b75505Sopenharmony_ci		wpabuf_put_str(buf, p->osu_nai2);
829e5b75505Sopenharmony_ci	} else {
830e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 0);
831e5b75505Sopenharmony_ci	}
832e5b75505Sopenharmony_ci}
833e5b75505Sopenharmony_ci
834e5b75505Sopenharmony_ci
835e5b75505Sopenharmony_cistatic void anqp_add_osu_providers_nai_list(struct hostapd_data *hapd,
836e5b75505Sopenharmony_ci					    struct wpabuf *buf)
837e5b75505Sopenharmony_ci{
838e5b75505Sopenharmony_ci	if (hapd->conf->hs20_osu_providers_nai_count) {
839e5b75505Sopenharmony_ci		size_t i;
840e5b75505Sopenharmony_ci		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
841e5b75505Sopenharmony_ci		wpabuf_put_be24(buf, OUI_WFA);
842e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
843e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
844e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 0); /* Reserved */
845e5b75505Sopenharmony_ci
846e5b75505Sopenharmony_ci		for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
847e5b75505Sopenharmony_ci			anqp_add_osu_provider_nai(
848e5b75505Sopenharmony_ci				buf, &hapd->conf->hs20_osu_providers[i]);
849e5b75505Sopenharmony_ci		}
850e5b75505Sopenharmony_ci
851e5b75505Sopenharmony_ci		gas_anqp_set_element_len(buf, len);
852e5b75505Sopenharmony_ci	}
853e5b75505Sopenharmony_ci}
854e5b75505Sopenharmony_ci
855e5b75505Sopenharmony_ci
856e5b75505Sopenharmony_cistatic void anqp_add_icon_binary_file(struct hostapd_data *hapd,
857e5b75505Sopenharmony_ci				      struct wpabuf *buf,
858e5b75505Sopenharmony_ci				      const u8 *name, size_t name_len)
859e5b75505Sopenharmony_ci{
860e5b75505Sopenharmony_ci	struct hs20_icon *icon;
861e5b75505Sopenharmony_ci	size_t i;
862e5b75505Sopenharmony_ci	u8 *len;
863e5b75505Sopenharmony_ci
864e5b75505Sopenharmony_ci	wpa_hexdump_ascii(MSG_DEBUG, "HS 2.0: Requested Icon Filename",
865e5b75505Sopenharmony_ci			  name, name_len);
866e5b75505Sopenharmony_ci	for (i = 0; i < hapd->conf->hs20_icons_count; i++) {
867e5b75505Sopenharmony_ci		icon = &hapd->conf->hs20_icons[i];
868e5b75505Sopenharmony_ci		if (name_len == os_strlen(icon->name) &&
869e5b75505Sopenharmony_ci		    os_memcmp(name, icon->name, name_len) == 0)
870e5b75505Sopenharmony_ci			break;
871e5b75505Sopenharmony_ci	}
872e5b75505Sopenharmony_ci
873e5b75505Sopenharmony_ci	if (i < hapd->conf->hs20_icons_count)
874e5b75505Sopenharmony_ci		icon = &hapd->conf->hs20_icons[i];
875e5b75505Sopenharmony_ci	else
876e5b75505Sopenharmony_ci		icon = NULL;
877e5b75505Sopenharmony_ci
878e5b75505Sopenharmony_ci	len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
879e5b75505Sopenharmony_ci	wpabuf_put_be24(buf, OUI_WFA);
880e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
881e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, HS20_STYPE_ICON_BINARY_FILE);
882e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 0); /* Reserved */
883e5b75505Sopenharmony_ci
884e5b75505Sopenharmony_ci	if (icon) {
885e5b75505Sopenharmony_ci		char *data;
886e5b75505Sopenharmony_ci		size_t data_len;
887e5b75505Sopenharmony_ci
888e5b75505Sopenharmony_ci		data = os_readfile(icon->file, &data_len);
889e5b75505Sopenharmony_ci		if (data == NULL || data_len > 65535) {
890e5b75505Sopenharmony_ci			wpabuf_put_u8(buf, 2); /* Download Status:
891e5b75505Sopenharmony_ci						* Unspecified file error */
892e5b75505Sopenharmony_ci			wpabuf_put_u8(buf, 0);
893e5b75505Sopenharmony_ci			wpabuf_put_le16(buf, 0);
894e5b75505Sopenharmony_ci		} else {
895e5b75505Sopenharmony_ci			wpabuf_put_u8(buf, 0); /* Download Status: Success */
896e5b75505Sopenharmony_ci			wpabuf_put_u8(buf, os_strlen(icon->type));
897e5b75505Sopenharmony_ci			wpabuf_put_str(buf, icon->type);
898e5b75505Sopenharmony_ci			wpabuf_put_le16(buf, data_len);
899e5b75505Sopenharmony_ci			wpabuf_put_data(buf, data, data_len);
900e5b75505Sopenharmony_ci		}
901e5b75505Sopenharmony_ci		os_free(data);
902e5b75505Sopenharmony_ci	} else {
903e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 1); /* Download Status: File not found */
904e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 0);
905e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, 0);
906e5b75505Sopenharmony_ci	}
907e5b75505Sopenharmony_ci
908e5b75505Sopenharmony_ci	gas_anqp_set_element_len(buf, len);
909e5b75505Sopenharmony_ci}
910e5b75505Sopenharmony_ci
911e5b75505Sopenharmony_ci
912e5b75505Sopenharmony_cistatic void anqp_add_operator_icon_metadata(struct hostapd_data *hapd,
913e5b75505Sopenharmony_ci					    struct wpabuf *buf)
914e5b75505Sopenharmony_ci{
915e5b75505Sopenharmony_ci	struct hostapd_bss_config *bss = hapd->conf;
916e5b75505Sopenharmony_ci	size_t i;
917e5b75505Sopenharmony_ci	u8 *len;
918e5b75505Sopenharmony_ci
919e5b75505Sopenharmony_ci	if (!bss->hs20_operator_icon_count)
920e5b75505Sopenharmony_ci		return;
921e5b75505Sopenharmony_ci
922e5b75505Sopenharmony_ci	len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
923e5b75505Sopenharmony_ci
924e5b75505Sopenharmony_ci	wpabuf_put_be24(buf, OUI_WFA);
925e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
926e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
927e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 0); /* Reserved */
928e5b75505Sopenharmony_ci
929e5b75505Sopenharmony_ci	for (i = 0; i < bss->hs20_operator_icon_count; i++)
930e5b75505Sopenharmony_ci		anqp_add_icon(buf, bss, bss->hs20_operator_icon[i]);
931e5b75505Sopenharmony_ci
932e5b75505Sopenharmony_ci	gas_anqp_set_element_len(buf, len);
933e5b75505Sopenharmony_ci}
934e5b75505Sopenharmony_ci
935e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */
936e5b75505Sopenharmony_ci
937e5b75505Sopenharmony_ci
938e5b75505Sopenharmony_ci#ifdef CONFIG_MBO
939e5b75505Sopenharmony_cistatic void anqp_add_mbo_cell_data_conn_pref(struct hostapd_data *hapd,
940e5b75505Sopenharmony_ci					     struct wpabuf *buf)
941e5b75505Sopenharmony_ci{
942e5b75505Sopenharmony_ci	if (hapd->conf->mbo_cell_data_conn_pref >= 0) {
943e5b75505Sopenharmony_ci		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
944e5b75505Sopenharmony_ci		wpabuf_put_be24(buf, OUI_WFA);
945e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, MBO_ANQP_OUI_TYPE);
946e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, MBO_ANQP_SUBTYPE_CELL_CONN_PREF);
947e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, hapd->conf->mbo_cell_data_conn_pref);
948e5b75505Sopenharmony_ci		gas_anqp_set_element_len(buf, len);
949e5b75505Sopenharmony_ci	}
950e5b75505Sopenharmony_ci}
951e5b75505Sopenharmony_ci#endif /* CONFIG_MBO */
952e5b75505Sopenharmony_ci
953e5b75505Sopenharmony_ci
954e5b75505Sopenharmony_cistatic size_t anqp_get_required_len(struct hostapd_data *hapd,
955e5b75505Sopenharmony_ci				    const u16 *infoid,
956e5b75505Sopenharmony_ci				    unsigned int num_infoid)
957e5b75505Sopenharmony_ci{
958e5b75505Sopenharmony_ci	size_t len = 0;
959e5b75505Sopenharmony_ci	unsigned int i;
960e5b75505Sopenharmony_ci
961e5b75505Sopenharmony_ci	for (i = 0; i < num_infoid; i++) {
962e5b75505Sopenharmony_ci		struct anqp_element *elem = get_anqp_elem(hapd, infoid[i]);
963e5b75505Sopenharmony_ci
964e5b75505Sopenharmony_ci		if (elem)
965e5b75505Sopenharmony_ci			len += 2 + 2 + wpabuf_len(elem->payload);
966e5b75505Sopenharmony_ci	}
967e5b75505Sopenharmony_ci
968e5b75505Sopenharmony_ci	return len;
969e5b75505Sopenharmony_ci}
970e5b75505Sopenharmony_ci
971e5b75505Sopenharmony_ci
972e5b75505Sopenharmony_cistatic struct wpabuf *
973e5b75505Sopenharmony_cigas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
974e5b75505Sopenharmony_ci				unsigned int request,
975e5b75505Sopenharmony_ci				const u8 *home_realm, size_t home_realm_len,
976e5b75505Sopenharmony_ci				const u8 *icon_name, size_t icon_name_len,
977e5b75505Sopenharmony_ci				const u16 *extra_req,
978e5b75505Sopenharmony_ci				unsigned int num_extra_req)
979e5b75505Sopenharmony_ci{
980e5b75505Sopenharmony_ci	struct wpabuf *buf;
981e5b75505Sopenharmony_ci	size_t len;
982e5b75505Sopenharmony_ci	unsigned int i;
983e5b75505Sopenharmony_ci
984e5b75505Sopenharmony_ci	len = 1400;
985e5b75505Sopenharmony_ci	if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
986e5b75505Sopenharmony_ci		len += 1000;
987e5b75505Sopenharmony_ci	if (request & ANQP_REQ_ICON_REQUEST)
988e5b75505Sopenharmony_ci		len += 65536;
989e5b75505Sopenharmony_ci#ifdef CONFIG_FILS
990e5b75505Sopenharmony_ci	if (request & ANQP_FILS_REALM_INFO)
991e5b75505Sopenharmony_ci		len += 2 * dl_list_len(&hapd->conf->fils_realms);
992e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */
993e5b75505Sopenharmony_ci	len += anqp_get_required_len(hapd, extra_req, num_extra_req);
994e5b75505Sopenharmony_ci
995e5b75505Sopenharmony_ci	buf = wpabuf_alloc(len);
996e5b75505Sopenharmony_ci	if (buf == NULL)
997e5b75505Sopenharmony_ci		return NULL;
998e5b75505Sopenharmony_ci
999e5b75505Sopenharmony_ci	if (request & ANQP_REQ_CAPABILITY_LIST)
1000e5b75505Sopenharmony_ci		anqp_add_capab_list(hapd, buf);
1001e5b75505Sopenharmony_ci	if (request & ANQP_REQ_VENUE_NAME)
1002e5b75505Sopenharmony_ci		anqp_add_venue_name(hapd, buf);
1003e5b75505Sopenharmony_ci	if (request & ANQP_REQ_EMERGENCY_CALL_NUMBER)
1004e5b75505Sopenharmony_ci		anqp_add_elem(hapd, buf, ANQP_EMERGENCY_CALL_NUMBER);
1005e5b75505Sopenharmony_ci	if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
1006e5b75505Sopenharmony_ci		anqp_add_network_auth_type(hapd, buf);
1007e5b75505Sopenharmony_ci	if (request & ANQP_REQ_ROAMING_CONSORTIUM)
1008e5b75505Sopenharmony_ci		anqp_add_roaming_consortium(hapd, buf);
1009e5b75505Sopenharmony_ci	if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY)
1010e5b75505Sopenharmony_ci		anqp_add_ip_addr_type_availability(hapd, buf);
1011e5b75505Sopenharmony_ci	if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
1012e5b75505Sopenharmony_ci		anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len,
1013e5b75505Sopenharmony_ci				   request & ANQP_REQ_NAI_REALM,
1014e5b75505Sopenharmony_ci				   request & ANQP_REQ_NAI_HOME_REALM);
1015e5b75505Sopenharmony_ci	if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
1016e5b75505Sopenharmony_ci		anqp_add_3gpp_cellular_network(hapd, buf);
1017e5b75505Sopenharmony_ci	if (request & ANQP_REQ_AP_GEOSPATIAL_LOCATION)
1018e5b75505Sopenharmony_ci		anqp_add_elem(hapd, buf, ANQP_AP_GEOSPATIAL_LOCATION);
1019e5b75505Sopenharmony_ci	if (request & ANQP_REQ_AP_CIVIC_LOCATION)
1020e5b75505Sopenharmony_ci		anqp_add_elem(hapd, buf, ANQP_AP_CIVIC_LOCATION);
1021e5b75505Sopenharmony_ci	if (request & ANQP_REQ_AP_LOCATION_PUBLIC_URI)
1022e5b75505Sopenharmony_ci		anqp_add_elem(hapd, buf, ANQP_AP_LOCATION_PUBLIC_URI);
1023e5b75505Sopenharmony_ci	if (request & ANQP_REQ_DOMAIN_NAME)
1024e5b75505Sopenharmony_ci		anqp_add_domain_name(hapd, buf);
1025e5b75505Sopenharmony_ci	if (request & ANQP_REQ_EMERGENCY_ALERT_URI)
1026e5b75505Sopenharmony_ci		anqp_add_elem(hapd, buf, ANQP_EMERGENCY_ALERT_URI);
1027e5b75505Sopenharmony_ci	if (request & ANQP_REQ_TDLS_CAPABILITY)
1028e5b75505Sopenharmony_ci		anqp_add_elem(hapd, buf, ANQP_TDLS_CAPABILITY);
1029e5b75505Sopenharmony_ci	if (request & ANQP_REQ_EMERGENCY_NAI)
1030e5b75505Sopenharmony_ci		anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
1031e5b75505Sopenharmony_ci
1032e5b75505Sopenharmony_ci	for (i = 0; i < num_extra_req; i++) {
1033e5b75505Sopenharmony_ci#ifdef CONFIG_FILS
1034e5b75505Sopenharmony_ci		if (extra_req[i] == ANQP_FILS_REALM_INFO) {
1035e5b75505Sopenharmony_ci			anqp_add_fils_realm_info(hapd, buf);
1036e5b75505Sopenharmony_ci			continue;
1037e5b75505Sopenharmony_ci		}
1038e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */
1039e5b75505Sopenharmony_ci		if (extra_req[i] == ANQP_VENUE_URL) {
1040e5b75505Sopenharmony_ci			anqp_add_venue_url(hapd, buf);
1041e5b75505Sopenharmony_ci			continue;
1042e5b75505Sopenharmony_ci		}
1043e5b75505Sopenharmony_ci		anqp_add_elem(hapd, buf, extra_req[i]);
1044e5b75505Sopenharmony_ci	}
1045e5b75505Sopenharmony_ci
1046e5b75505Sopenharmony_ci#ifdef CONFIG_HS20
1047e5b75505Sopenharmony_ci	if (request & ANQP_REQ_HS_CAPABILITY_LIST)
1048e5b75505Sopenharmony_ci		anqp_add_hs_capab_list(hapd, buf);
1049e5b75505Sopenharmony_ci	if (request & ANQP_REQ_OPERATOR_FRIENDLY_NAME)
1050e5b75505Sopenharmony_ci		anqp_add_operator_friendly_name(hapd, buf);
1051e5b75505Sopenharmony_ci	if (request & ANQP_REQ_WAN_METRICS)
1052e5b75505Sopenharmony_ci		anqp_add_wan_metrics(hapd, buf);
1053e5b75505Sopenharmony_ci	if (request & ANQP_REQ_CONNECTION_CAPABILITY)
1054e5b75505Sopenharmony_ci		anqp_add_connection_capability(hapd, buf);
1055e5b75505Sopenharmony_ci	if (request & ANQP_REQ_OPERATING_CLASS)
1056e5b75505Sopenharmony_ci		anqp_add_operating_class(hapd, buf);
1057e5b75505Sopenharmony_ci	if (request & ANQP_REQ_OSU_PROVIDERS_LIST)
1058e5b75505Sopenharmony_ci		anqp_add_osu_providers_list(hapd, buf);
1059e5b75505Sopenharmony_ci	if (request & ANQP_REQ_ICON_REQUEST)
1060e5b75505Sopenharmony_ci		anqp_add_icon_binary_file(hapd, buf, icon_name, icon_name_len);
1061e5b75505Sopenharmony_ci	if (request & ANQP_REQ_OPERATOR_ICON_METADATA)
1062e5b75505Sopenharmony_ci		anqp_add_operator_icon_metadata(hapd, buf);
1063e5b75505Sopenharmony_ci	if (request & ANQP_REQ_OSU_PROVIDERS_NAI_LIST)
1064e5b75505Sopenharmony_ci		anqp_add_osu_providers_nai_list(hapd, buf);
1065e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */
1066e5b75505Sopenharmony_ci
1067e5b75505Sopenharmony_ci#ifdef CONFIG_MBO
1068e5b75505Sopenharmony_ci	if (request & ANQP_REQ_MBO_CELL_DATA_CONN_PREF)
1069e5b75505Sopenharmony_ci		anqp_add_mbo_cell_data_conn_pref(hapd, buf);
1070e5b75505Sopenharmony_ci#endif /* CONFIG_MBO */
1071e5b75505Sopenharmony_ci
1072e5b75505Sopenharmony_ci	return buf;
1073e5b75505Sopenharmony_ci}
1074e5b75505Sopenharmony_ci
1075e5b75505Sopenharmony_ci
1076e5b75505Sopenharmony_ci#define ANQP_MAX_EXTRA_REQ 20
1077e5b75505Sopenharmony_ci
1078e5b75505Sopenharmony_cistruct anqp_query_info {
1079e5b75505Sopenharmony_ci	unsigned int request;
1080e5b75505Sopenharmony_ci	const u8 *home_realm_query;
1081e5b75505Sopenharmony_ci	size_t home_realm_query_len;
1082e5b75505Sopenharmony_ci	const u8 *icon_name;
1083e5b75505Sopenharmony_ci	size_t icon_name_len;
1084e5b75505Sopenharmony_ci	int p2p_sd;
1085e5b75505Sopenharmony_ci	u16 extra_req[ANQP_MAX_EXTRA_REQ];
1086e5b75505Sopenharmony_ci	unsigned int num_extra_req;
1087e5b75505Sopenharmony_ci};
1088e5b75505Sopenharmony_ci
1089e5b75505Sopenharmony_ci
1090e5b75505Sopenharmony_cistatic void set_anqp_req(unsigned int bit, const char *name, int local,
1091e5b75505Sopenharmony_ci			 struct anqp_query_info *qi)
1092e5b75505Sopenharmony_ci{
1093e5b75505Sopenharmony_ci	qi->request |= bit;
1094e5b75505Sopenharmony_ci	if (local) {
1095e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name);
1096e5b75505Sopenharmony_ci	} else {
1097e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: %s not available", name);
1098e5b75505Sopenharmony_ci	}
1099e5b75505Sopenharmony_ci}
1100e5b75505Sopenharmony_ci
1101e5b75505Sopenharmony_ci
1102e5b75505Sopenharmony_cistatic void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
1103e5b75505Sopenharmony_ci				  struct anqp_query_info *qi)
1104e5b75505Sopenharmony_ci{
1105e5b75505Sopenharmony_ci	switch (info_id) {
1106e5b75505Sopenharmony_ci	case ANQP_CAPABILITY_LIST:
1107e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1,
1108e5b75505Sopenharmony_ci			     qi);
1109e5b75505Sopenharmony_ci		break;
1110e5b75505Sopenharmony_ci	case ANQP_VENUE_NAME:
1111e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
1112e5b75505Sopenharmony_ci			     hapd->conf->venue_name != NULL, qi);
1113e5b75505Sopenharmony_ci		break;
1114e5b75505Sopenharmony_ci	case ANQP_EMERGENCY_CALL_NUMBER:
1115e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_EMERGENCY_CALL_NUMBER,
1116e5b75505Sopenharmony_ci			     "Emergency Call Number",
1117e5b75505Sopenharmony_ci			     get_anqp_elem(hapd, info_id) != NULL, qi);
1118e5b75505Sopenharmony_ci		break;
1119e5b75505Sopenharmony_ci	case ANQP_NETWORK_AUTH_TYPE:
1120e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
1121e5b75505Sopenharmony_ci			     hapd->conf->network_auth_type != NULL, qi);
1122e5b75505Sopenharmony_ci		break;
1123e5b75505Sopenharmony_ci	case ANQP_ROAMING_CONSORTIUM:
1124e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
1125e5b75505Sopenharmony_ci			     hapd->conf->roaming_consortium != NULL, qi);
1126e5b75505Sopenharmony_ci		break;
1127e5b75505Sopenharmony_ci	case ANQP_IP_ADDR_TYPE_AVAILABILITY:
1128e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY,
1129e5b75505Sopenharmony_ci			     "IP Addr Type Availability",
1130e5b75505Sopenharmony_ci			     hapd->conf->ipaddr_type_configured, qi);
1131e5b75505Sopenharmony_ci		break;
1132e5b75505Sopenharmony_ci	case ANQP_NAI_REALM:
1133e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm",
1134e5b75505Sopenharmony_ci			     hapd->conf->nai_realm_data != NULL, qi);
1135e5b75505Sopenharmony_ci		break;
1136e5b75505Sopenharmony_ci	case ANQP_3GPP_CELLULAR_NETWORK:
1137e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
1138e5b75505Sopenharmony_ci			     "3GPP Cellular Network",
1139e5b75505Sopenharmony_ci			     hapd->conf->anqp_3gpp_cell_net != NULL, qi);
1140e5b75505Sopenharmony_ci		break;
1141e5b75505Sopenharmony_ci	case ANQP_AP_GEOSPATIAL_LOCATION:
1142e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_AP_GEOSPATIAL_LOCATION,
1143e5b75505Sopenharmony_ci			     "AP Geospatial Location",
1144e5b75505Sopenharmony_ci			     get_anqp_elem(hapd, info_id) != NULL, qi);
1145e5b75505Sopenharmony_ci		break;
1146e5b75505Sopenharmony_ci	case ANQP_AP_CIVIC_LOCATION:
1147e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_AP_CIVIC_LOCATION,
1148e5b75505Sopenharmony_ci			     "AP Civic Location",
1149e5b75505Sopenharmony_ci			     get_anqp_elem(hapd, info_id) != NULL, qi);
1150e5b75505Sopenharmony_ci		break;
1151e5b75505Sopenharmony_ci	case ANQP_AP_LOCATION_PUBLIC_URI:
1152e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_AP_LOCATION_PUBLIC_URI,
1153e5b75505Sopenharmony_ci			     "AP Location Public URI",
1154e5b75505Sopenharmony_ci			     get_anqp_elem(hapd, info_id) != NULL, qi);
1155e5b75505Sopenharmony_ci		break;
1156e5b75505Sopenharmony_ci	case ANQP_DOMAIN_NAME:
1157e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
1158e5b75505Sopenharmony_ci			     hapd->conf->domain_name != NULL, qi);
1159e5b75505Sopenharmony_ci		break;
1160e5b75505Sopenharmony_ci	case ANQP_EMERGENCY_ALERT_URI:
1161e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_EMERGENCY_ALERT_URI,
1162e5b75505Sopenharmony_ci			     "Emergency Alert URI",
1163e5b75505Sopenharmony_ci			     get_anqp_elem(hapd, info_id) != NULL, qi);
1164e5b75505Sopenharmony_ci		break;
1165e5b75505Sopenharmony_ci	case ANQP_TDLS_CAPABILITY:
1166e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_TDLS_CAPABILITY,
1167e5b75505Sopenharmony_ci			     "TDLS Capability",
1168e5b75505Sopenharmony_ci			     get_anqp_elem(hapd, info_id) != NULL, qi);
1169e5b75505Sopenharmony_ci		break;
1170e5b75505Sopenharmony_ci	case ANQP_EMERGENCY_NAI:
1171e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_EMERGENCY_NAI,
1172e5b75505Sopenharmony_ci			     "Emergency NAI",
1173e5b75505Sopenharmony_ci			     get_anqp_elem(hapd, info_id) != NULL, qi);
1174e5b75505Sopenharmony_ci		break;
1175e5b75505Sopenharmony_ci	default:
1176e5b75505Sopenharmony_ci#ifdef CONFIG_FILS
1177e5b75505Sopenharmony_ci		if (info_id == ANQP_FILS_REALM_INFO &&
1178e5b75505Sopenharmony_ci		    !dl_list_empty(&hapd->conf->fils_realms)) {
1179e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
1180e5b75505Sopenharmony_ci				   "ANQP: FILS Realm Information (local)");
1181e5b75505Sopenharmony_ci		} else
1182e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */
1183e5b75505Sopenharmony_ci		if (info_id == ANQP_VENUE_URL && hapd->conf->venue_url) {
1184e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
1185e5b75505Sopenharmony_ci				   "ANQP: Venue URL (local)");
1186e5b75505Sopenharmony_ci		} else if (!get_anqp_elem(hapd, info_id)) {
1187e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
1188e5b75505Sopenharmony_ci				   info_id);
1189e5b75505Sopenharmony_ci			break;
1190e5b75505Sopenharmony_ci		}
1191e5b75505Sopenharmony_ci		if (qi->num_extra_req == ANQP_MAX_EXTRA_REQ) {
1192e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
1193e5b75505Sopenharmony_ci				   "ANQP: No more room for extra requests - ignore Info Id %u",
1194e5b75505Sopenharmony_ci				   info_id);
1195e5b75505Sopenharmony_ci			break;
1196e5b75505Sopenharmony_ci		}
1197e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: Info Id %u (local)", info_id);
1198e5b75505Sopenharmony_ci		qi->extra_req[qi->num_extra_req] = info_id;
1199e5b75505Sopenharmony_ci		qi->num_extra_req++;
1200e5b75505Sopenharmony_ci		break;
1201e5b75505Sopenharmony_ci	}
1202e5b75505Sopenharmony_ci}
1203e5b75505Sopenharmony_ci
1204e5b75505Sopenharmony_ci
1205e5b75505Sopenharmony_cistatic void rx_anqp_query_list(struct hostapd_data *hapd,
1206e5b75505Sopenharmony_ci			       const u8 *pos, const u8 *end,
1207e5b75505Sopenharmony_ci			       struct anqp_query_info *qi)
1208e5b75505Sopenharmony_ci{
1209e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
1210e5b75505Sopenharmony_ci		   (unsigned int) (end - pos) / 2);
1211e5b75505Sopenharmony_ci
1212e5b75505Sopenharmony_ci	while (end - pos >= 2) {
1213e5b75505Sopenharmony_ci		rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
1214e5b75505Sopenharmony_ci		pos += 2;
1215e5b75505Sopenharmony_ci	}
1216e5b75505Sopenharmony_ci}
1217e5b75505Sopenharmony_ci
1218e5b75505Sopenharmony_ci
1219e5b75505Sopenharmony_ci#ifdef CONFIG_HS20
1220e5b75505Sopenharmony_ci
1221e5b75505Sopenharmony_cistatic void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
1222e5b75505Sopenharmony_ci				  struct anqp_query_info *qi)
1223e5b75505Sopenharmony_ci{
1224e5b75505Sopenharmony_ci	switch (subtype) {
1225e5b75505Sopenharmony_ci	case HS20_STYPE_CAPABILITY_LIST:
1226e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List",
1227e5b75505Sopenharmony_ci			     1, qi);
1228e5b75505Sopenharmony_ci		break;
1229e5b75505Sopenharmony_ci	case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
1230e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME,
1231e5b75505Sopenharmony_ci			     "Operator Friendly Name",
1232e5b75505Sopenharmony_ci			     hapd->conf->hs20_oper_friendly_name != NULL, qi);
1233e5b75505Sopenharmony_ci		break;
1234e5b75505Sopenharmony_ci	case HS20_STYPE_WAN_METRICS:
1235e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics",
1236e5b75505Sopenharmony_ci			     hapd->conf->hs20_wan_metrics != NULL, qi);
1237e5b75505Sopenharmony_ci		break;
1238e5b75505Sopenharmony_ci	case HS20_STYPE_CONNECTION_CAPABILITY:
1239e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY,
1240e5b75505Sopenharmony_ci			     "Connection Capability",
1241e5b75505Sopenharmony_ci			     hapd->conf->hs20_connection_capability != NULL,
1242e5b75505Sopenharmony_ci			     qi);
1243e5b75505Sopenharmony_ci		break;
1244e5b75505Sopenharmony_ci	case HS20_STYPE_OPERATING_CLASS:
1245e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class",
1246e5b75505Sopenharmony_ci			     hapd->conf->hs20_operating_class != NULL, qi);
1247e5b75505Sopenharmony_ci		break;
1248e5b75505Sopenharmony_ci	case HS20_STYPE_OSU_PROVIDERS_LIST:
1249e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list",
1250e5b75505Sopenharmony_ci			     hapd->conf->hs20_osu_providers_count, qi);
1251e5b75505Sopenharmony_ci		break;
1252e5b75505Sopenharmony_ci	case HS20_STYPE_OPERATOR_ICON_METADATA:
1253e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_OPERATOR_ICON_METADATA,
1254e5b75505Sopenharmony_ci			     "Operator Icon Metadata",
1255e5b75505Sopenharmony_ci			     hapd->conf->hs20_operator_icon_count, qi);
1256e5b75505Sopenharmony_ci		break;
1257e5b75505Sopenharmony_ci	case HS20_STYPE_OSU_PROVIDERS_NAI_LIST:
1258e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_OSU_PROVIDERS_NAI_LIST,
1259e5b75505Sopenharmony_ci			     "OSU Providers NAI List",
1260e5b75505Sopenharmony_ci			     hapd->conf->hs20_osu_providers_nai_count, qi);
1261e5b75505Sopenharmony_ci		break;
1262e5b75505Sopenharmony_ci	default:
1263e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
1264e5b75505Sopenharmony_ci			   subtype);
1265e5b75505Sopenharmony_ci		break;
1266e5b75505Sopenharmony_ci	}
1267e5b75505Sopenharmony_ci}
1268e5b75505Sopenharmony_ci
1269e5b75505Sopenharmony_ci
1270e5b75505Sopenharmony_cistatic void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd,
1271e5b75505Sopenharmony_ci				      const u8 *pos, const u8 *end,
1272e5b75505Sopenharmony_ci				      struct anqp_query_info *qi)
1273e5b75505Sopenharmony_ci{
1274e5b75505Sopenharmony_ci	qi->request |= ANQP_REQ_NAI_HOME_REALM;
1275e5b75505Sopenharmony_ci	qi->home_realm_query = pos;
1276e5b75505Sopenharmony_ci	qi->home_realm_query_len = end - pos;
1277e5b75505Sopenharmony_ci	if (hapd->conf->nai_realm_data != NULL) {
1278e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query "
1279e5b75505Sopenharmony_ci			   "(local)");
1280e5b75505Sopenharmony_ci	} else {
1281e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not "
1282e5b75505Sopenharmony_ci			   "available");
1283e5b75505Sopenharmony_ci	}
1284e5b75505Sopenharmony_ci}
1285e5b75505Sopenharmony_ci
1286e5b75505Sopenharmony_ci
1287e5b75505Sopenharmony_cistatic void rx_anqp_hs_icon_request(struct hostapd_data *hapd,
1288e5b75505Sopenharmony_ci				    const u8 *pos, const u8 *end,
1289e5b75505Sopenharmony_ci				    struct anqp_query_info *qi)
1290e5b75505Sopenharmony_ci{
1291e5b75505Sopenharmony_ci	qi->request |= ANQP_REQ_ICON_REQUEST;
1292e5b75505Sopenharmony_ci	qi->icon_name = pos;
1293e5b75505Sopenharmony_ci	qi->icon_name_len = end - pos;
1294e5b75505Sopenharmony_ci	if (hapd->conf->hs20_icons_count) {
1295e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query "
1296e5b75505Sopenharmony_ci			   "(local)");
1297e5b75505Sopenharmony_ci	} else {
1298e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query not "
1299e5b75505Sopenharmony_ci			   "available");
1300e5b75505Sopenharmony_ci	}
1301e5b75505Sopenharmony_ci}
1302e5b75505Sopenharmony_ci
1303e5b75505Sopenharmony_ci
1304e5b75505Sopenharmony_cistatic void rx_anqp_vendor_specific_hs20(struct hostapd_data *hapd,
1305e5b75505Sopenharmony_ci					 const u8 *pos, const u8 *end,
1306e5b75505Sopenharmony_ci					 struct anqp_query_info *qi)
1307e5b75505Sopenharmony_ci{
1308e5b75505Sopenharmony_ci	u8 subtype;
1309e5b75505Sopenharmony_ci
1310e5b75505Sopenharmony_ci	if (end - pos <= 1)
1311e5b75505Sopenharmony_ci		return;
1312e5b75505Sopenharmony_ci
1313e5b75505Sopenharmony_ci	subtype = *pos++;
1314e5b75505Sopenharmony_ci	pos++; /* Reserved */
1315e5b75505Sopenharmony_ci	switch (subtype) {
1316e5b75505Sopenharmony_ci	case HS20_STYPE_QUERY_LIST:
1317e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List");
1318e5b75505Sopenharmony_ci		while (pos < end) {
1319e5b75505Sopenharmony_ci			rx_anqp_hs_query_list(hapd, *pos, qi);
1320e5b75505Sopenharmony_ci			pos++;
1321e5b75505Sopenharmony_ci		}
1322e5b75505Sopenharmony_ci		break;
1323e5b75505Sopenharmony_ci	case HS20_STYPE_NAI_HOME_REALM_QUERY:
1324e5b75505Sopenharmony_ci		rx_anqp_hs_nai_home_realm(hapd, pos, end, qi);
1325e5b75505Sopenharmony_ci		break;
1326e5b75505Sopenharmony_ci	case HS20_STYPE_ICON_REQUEST:
1327e5b75505Sopenharmony_ci		rx_anqp_hs_icon_request(hapd, pos, end, qi);
1328e5b75505Sopenharmony_ci		break;
1329e5b75505Sopenharmony_ci	default:
1330e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype "
1331e5b75505Sopenharmony_ci			   "%u", subtype);
1332e5b75505Sopenharmony_ci		break;
1333e5b75505Sopenharmony_ci	}
1334e5b75505Sopenharmony_ci}
1335e5b75505Sopenharmony_ci
1336e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */
1337e5b75505Sopenharmony_ci
1338e5b75505Sopenharmony_ci
1339e5b75505Sopenharmony_ci#ifdef CONFIG_P2P
1340e5b75505Sopenharmony_cistatic void rx_anqp_vendor_specific_p2p(struct hostapd_data *hapd,
1341e5b75505Sopenharmony_ci					struct anqp_query_info *qi)
1342e5b75505Sopenharmony_ci{
1343e5b75505Sopenharmony_ci	/*
1344e5b75505Sopenharmony_ci	 * This is for P2P SD and will be taken care of by the P2P
1345e5b75505Sopenharmony_ci	 * implementation. This query needs to be ignored in the generic
1346e5b75505Sopenharmony_ci	 * GAS server to avoid duplicated response.
1347e5b75505Sopenharmony_ci	 */
1348e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
1349e5b75505Sopenharmony_ci		   "ANQP: Ignore WFA vendor type %u (P2P SD) in generic GAS server",
1350e5b75505Sopenharmony_ci		   P2P_OUI_TYPE);
1351e5b75505Sopenharmony_ci	qi->p2p_sd = 1;
1352e5b75505Sopenharmony_ci	return;
1353e5b75505Sopenharmony_ci}
1354e5b75505Sopenharmony_ci#endif /* CONFIG_P2P */
1355e5b75505Sopenharmony_ci
1356e5b75505Sopenharmony_ci
1357e5b75505Sopenharmony_ci#ifdef CONFIG_MBO
1358e5b75505Sopenharmony_ci
1359e5b75505Sopenharmony_cistatic void rx_anqp_mbo_query_list(struct hostapd_data *hapd, u8 subtype,
1360e5b75505Sopenharmony_ci				  struct anqp_query_info *qi)
1361e5b75505Sopenharmony_ci{
1362e5b75505Sopenharmony_ci	switch (subtype) {
1363e5b75505Sopenharmony_ci	case MBO_ANQP_SUBTYPE_CELL_CONN_PREF:
1364e5b75505Sopenharmony_ci		set_anqp_req(ANQP_REQ_MBO_CELL_DATA_CONN_PREF,
1365e5b75505Sopenharmony_ci			     "Cellular Data Connection Preference",
1366e5b75505Sopenharmony_ci			     hapd->conf->mbo_cell_data_conn_pref >= 0, qi);
1367e5b75505Sopenharmony_ci		break;
1368e5b75505Sopenharmony_ci	default:
1369e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: Unsupported MBO subtype %u",
1370e5b75505Sopenharmony_ci			   subtype);
1371e5b75505Sopenharmony_ci		break;
1372e5b75505Sopenharmony_ci	}
1373e5b75505Sopenharmony_ci}
1374e5b75505Sopenharmony_ci
1375e5b75505Sopenharmony_ci
1376e5b75505Sopenharmony_cistatic void rx_anqp_vendor_specific_mbo(struct hostapd_data *hapd,
1377e5b75505Sopenharmony_ci					const u8 *pos, const u8 *end,
1378e5b75505Sopenharmony_ci					struct anqp_query_info *qi)
1379e5b75505Sopenharmony_ci{
1380e5b75505Sopenharmony_ci	u8 subtype;
1381e5b75505Sopenharmony_ci
1382e5b75505Sopenharmony_ci	if (end - pos < 1)
1383e5b75505Sopenharmony_ci		return;
1384e5b75505Sopenharmony_ci
1385e5b75505Sopenharmony_ci	subtype = *pos++;
1386e5b75505Sopenharmony_ci	switch (subtype) {
1387e5b75505Sopenharmony_ci	case MBO_ANQP_SUBTYPE_QUERY_LIST:
1388e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: MBO Query List");
1389e5b75505Sopenharmony_ci		while (pos < end) {
1390e5b75505Sopenharmony_ci			rx_anqp_mbo_query_list(hapd, *pos, qi);
1391e5b75505Sopenharmony_ci			pos++;
1392e5b75505Sopenharmony_ci		}
1393e5b75505Sopenharmony_ci		break;
1394e5b75505Sopenharmony_ci	default:
1395e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: Unsupported MBO query subtype %u",
1396e5b75505Sopenharmony_ci			   subtype);
1397e5b75505Sopenharmony_ci		break;
1398e5b75505Sopenharmony_ci	}
1399e5b75505Sopenharmony_ci}
1400e5b75505Sopenharmony_ci
1401e5b75505Sopenharmony_ci#endif /* CONFIG_MBO */
1402e5b75505Sopenharmony_ci
1403e5b75505Sopenharmony_ci
1404e5b75505Sopenharmony_cistatic void rx_anqp_vendor_specific(struct hostapd_data *hapd,
1405e5b75505Sopenharmony_ci				    const u8 *pos, const u8 *end,
1406e5b75505Sopenharmony_ci				    struct anqp_query_info *qi)
1407e5b75505Sopenharmony_ci{
1408e5b75505Sopenharmony_ci	u32 oui;
1409e5b75505Sopenharmony_ci
1410e5b75505Sopenharmony_ci	if (end - pos < 4) {
1411e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
1412e5b75505Sopenharmony_ci			   "Query element");
1413e5b75505Sopenharmony_ci		return;
1414e5b75505Sopenharmony_ci	}
1415e5b75505Sopenharmony_ci
1416e5b75505Sopenharmony_ci	oui = WPA_GET_BE24(pos);
1417e5b75505Sopenharmony_ci	pos += 3;
1418e5b75505Sopenharmony_ci	if (oui != OUI_WFA) {
1419e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
1420e5b75505Sopenharmony_ci			   oui);
1421e5b75505Sopenharmony_ci		return;
1422e5b75505Sopenharmony_ci	}
1423e5b75505Sopenharmony_ci
1424e5b75505Sopenharmony_ci	switch (*pos) {
1425e5b75505Sopenharmony_ci#ifdef CONFIG_P2P
1426e5b75505Sopenharmony_ci	case P2P_OUI_TYPE:
1427e5b75505Sopenharmony_ci		rx_anqp_vendor_specific_p2p(hapd, qi);
1428e5b75505Sopenharmony_ci		break;
1429e5b75505Sopenharmony_ci#endif /* CONFIG_P2P */
1430e5b75505Sopenharmony_ci#ifdef CONFIG_HS20
1431e5b75505Sopenharmony_ci	case HS20_ANQP_OUI_TYPE:
1432e5b75505Sopenharmony_ci		rx_anqp_vendor_specific_hs20(hapd, pos + 1, end, qi);
1433e5b75505Sopenharmony_ci		break;
1434e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */
1435e5b75505Sopenharmony_ci#ifdef CONFIG_MBO
1436e5b75505Sopenharmony_ci	case MBO_ANQP_OUI_TYPE:
1437e5b75505Sopenharmony_ci		rx_anqp_vendor_specific_mbo(hapd, pos + 1, end, qi);
1438e5b75505Sopenharmony_ci		break;
1439e5b75505Sopenharmony_ci#endif /* CONFIG_MBO */
1440e5b75505Sopenharmony_ci	default:
1441e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
1442e5b75505Sopenharmony_ci			   *pos);
1443e5b75505Sopenharmony_ci		break;
1444e5b75505Sopenharmony_ci	}
1445e5b75505Sopenharmony_ci}
1446e5b75505Sopenharmony_ci
1447e5b75505Sopenharmony_ci
1448e5b75505Sopenharmony_cistatic void gas_serv_req_local_processing(struct hostapd_data *hapd,
1449e5b75505Sopenharmony_ci					  const u8 *sa, u8 dialog_token,
1450e5b75505Sopenharmony_ci					  struct anqp_query_info *qi, int prot,
1451e5b75505Sopenharmony_ci					  int std_addr3)
1452e5b75505Sopenharmony_ci{
1453e5b75505Sopenharmony_ci	struct wpabuf *buf, *tx_buf;
1454e5b75505Sopenharmony_ci
1455e5b75505Sopenharmony_ci	buf = gas_serv_build_gas_resp_payload(hapd, qi->request,
1456e5b75505Sopenharmony_ci					      qi->home_realm_query,
1457e5b75505Sopenharmony_ci					      qi->home_realm_query_len,
1458e5b75505Sopenharmony_ci					      qi->icon_name, qi->icon_name_len,
1459e5b75505Sopenharmony_ci					      qi->extra_req, qi->num_extra_req);
1460e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
1461e5b75505Sopenharmony_ci			buf);
1462e5b75505Sopenharmony_ci	if (!buf)
1463e5b75505Sopenharmony_ci		return;
1464e5b75505Sopenharmony_ci#ifdef CONFIG_P2P
1465e5b75505Sopenharmony_ci	if (wpabuf_len(buf) == 0 && qi->p2p_sd) {
1466e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1467e5b75505Sopenharmony_ci			   "ANQP: Do not send response to P2P SD from generic GAS service (P2P SD implementation will process this)");
1468e5b75505Sopenharmony_ci		wpabuf_free(buf);
1469e5b75505Sopenharmony_ci		return;
1470e5b75505Sopenharmony_ci	}
1471e5b75505Sopenharmony_ci#endif /* CONFIG_P2P */
1472e5b75505Sopenharmony_ci
1473e5b75505Sopenharmony_ci	if (wpabuf_len(buf) > hapd->conf->gas_frag_limit ||
1474e5b75505Sopenharmony_ci	    hapd->conf->gas_comeback_delay) {
1475e5b75505Sopenharmony_ci		struct gas_dialog_info *di;
1476e5b75505Sopenharmony_ci		u16 comeback_delay = 1;
1477e5b75505Sopenharmony_ci
1478e5b75505Sopenharmony_ci		if (hapd->conf->gas_comeback_delay) {
1479e5b75505Sopenharmony_ci			/* Testing - allow overriding of the delay value */
1480e5b75505Sopenharmony_ci			comeback_delay = hapd->conf->gas_comeback_delay;
1481e5b75505Sopenharmony_ci		}
1482e5b75505Sopenharmony_ci
1483e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in "
1484e5b75505Sopenharmony_ci			   "initial response - use GAS comeback");
1485e5b75505Sopenharmony_ci		di = gas_dialog_create(hapd, sa, dialog_token);
1486e5b75505Sopenharmony_ci		if (!di) {
1487e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "ANQP: Could not create dialog "
1488e5b75505Sopenharmony_ci				   "for " MACSTR " (dialog token %u)",
1489e5b75505Sopenharmony_ci				   MAC2STR(sa), dialog_token);
1490e5b75505Sopenharmony_ci			wpabuf_free(buf);
1491e5b75505Sopenharmony_ci			tx_buf = gas_anqp_build_initial_resp_buf(
1492e5b75505Sopenharmony_ci				dialog_token, WLAN_STATUS_UNSPECIFIED_FAILURE,
1493e5b75505Sopenharmony_ci				0, NULL);
1494e5b75505Sopenharmony_ci		} else {
1495e5b75505Sopenharmony_ci			di->prot = prot;
1496e5b75505Sopenharmony_ci			di->sd_resp = buf;
1497e5b75505Sopenharmony_ci			di->sd_resp_pos = 0;
1498e5b75505Sopenharmony_ci			tx_buf = gas_anqp_build_initial_resp_buf(
1499e5b75505Sopenharmony_ci				dialog_token, WLAN_STATUS_SUCCESS,
1500e5b75505Sopenharmony_ci				comeback_delay, NULL);
1501e5b75505Sopenharmony_ci		}
1502e5b75505Sopenharmony_ci	} else {
1503e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)");
1504e5b75505Sopenharmony_ci		tx_buf = gas_anqp_build_initial_resp_buf(
1505e5b75505Sopenharmony_ci			dialog_token, WLAN_STATUS_SUCCESS, 0, buf);
1506e5b75505Sopenharmony_ci		wpabuf_free(buf);
1507e5b75505Sopenharmony_ci	}
1508e5b75505Sopenharmony_ci	if (!tx_buf)
1509e5b75505Sopenharmony_ci		return;
1510e5b75505Sopenharmony_ci	if (prot)
1511e5b75505Sopenharmony_ci		convert_to_protected_dual(tx_buf);
1512e5b75505Sopenharmony_ci	if (std_addr3)
1513e5b75505Sopenharmony_ci		hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
1514e5b75505Sopenharmony_ci					wpabuf_head(tx_buf),
1515e5b75505Sopenharmony_ci					wpabuf_len(tx_buf));
1516e5b75505Sopenharmony_ci	else
1517e5b75505Sopenharmony_ci		hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
1518e5b75505Sopenharmony_ci						 wpabuf_head(tx_buf),
1519e5b75505Sopenharmony_ci						 wpabuf_len(tx_buf));
1520e5b75505Sopenharmony_ci	wpabuf_free(tx_buf);
1521e5b75505Sopenharmony_ci}
1522e5b75505Sopenharmony_ci
1523e5b75505Sopenharmony_ci
1524e5b75505Sopenharmony_ci#ifdef CONFIG_DPP
1525e5b75505Sopenharmony_civoid gas_serv_req_dpp_processing(struct hostapd_data *hapd,
1526e5b75505Sopenharmony_ci				 const u8 *sa, u8 dialog_token,
1527e5b75505Sopenharmony_ci				 int prot, struct wpabuf *buf)
1528e5b75505Sopenharmony_ci{
1529e5b75505Sopenharmony_ci	struct wpabuf *tx_buf;
1530e5b75505Sopenharmony_ci
1531e5b75505Sopenharmony_ci	if (wpabuf_len(buf) > hapd->conf->gas_frag_limit ||
1532e5b75505Sopenharmony_ci	    hapd->conf->gas_comeback_delay) {
1533e5b75505Sopenharmony_ci		struct gas_dialog_info *di;
1534e5b75505Sopenharmony_ci		u16 comeback_delay = 1;
1535e5b75505Sopenharmony_ci
1536e5b75505Sopenharmony_ci		if (hapd->conf->gas_comeback_delay) {
1537e5b75505Sopenharmony_ci			/* Testing - allow overriding of the delay value */
1538e5b75505Sopenharmony_ci			comeback_delay = hapd->conf->gas_comeback_delay;
1539e5b75505Sopenharmony_ci		}
1540e5b75505Sopenharmony_ci
1541e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1542e5b75505Sopenharmony_ci			   "DPP: Too long response to fit in initial response - use GAS comeback");
1543e5b75505Sopenharmony_ci		di = gas_dialog_create(hapd, sa, dialog_token);
1544e5b75505Sopenharmony_ci		if (!di) {
1545e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "DPP: Could not create dialog for "
1546e5b75505Sopenharmony_ci				   MACSTR " (dialog token %u)",
1547e5b75505Sopenharmony_ci				   MAC2STR(sa), dialog_token);
1548e5b75505Sopenharmony_ci			wpabuf_free(buf);
1549e5b75505Sopenharmony_ci			tx_buf = gas_build_initial_resp(
1550e5b75505Sopenharmony_ci				dialog_token, WLAN_STATUS_UNSPECIFIED_FAILURE,
1551e5b75505Sopenharmony_ci				0, 10);
1552e5b75505Sopenharmony_ci			if (tx_buf)
1553e5b75505Sopenharmony_ci				gas_serv_write_dpp_adv_proto(tx_buf);
1554e5b75505Sopenharmony_ci		} else {
1555e5b75505Sopenharmony_ci			di->prot = prot;
1556e5b75505Sopenharmony_ci			di->sd_resp = buf;
1557e5b75505Sopenharmony_ci			di->sd_resp_pos = 0;
1558e5b75505Sopenharmony_ci			tx_buf = gas_build_initial_resp(
1559e5b75505Sopenharmony_ci				dialog_token, WLAN_STATUS_SUCCESS,
1560e5b75505Sopenharmony_ci				comeback_delay, 10);
1561e5b75505Sopenharmony_ci			if (tx_buf)
1562e5b75505Sopenharmony_ci				gas_serv_write_dpp_adv_proto(tx_buf);
1563e5b75505Sopenharmony_ci		}
1564e5b75505Sopenharmony_ci	} else {
1565e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1566e5b75505Sopenharmony_ci			   "DPP: GAS Initial response (no comeback)");
1567e5b75505Sopenharmony_ci		tx_buf = gas_build_initial_resp(
1568e5b75505Sopenharmony_ci			dialog_token, WLAN_STATUS_SUCCESS, 0,
1569e5b75505Sopenharmony_ci			10 + 2 + wpabuf_len(buf));
1570e5b75505Sopenharmony_ci		if (tx_buf) {
1571e5b75505Sopenharmony_ci			gas_serv_write_dpp_adv_proto(tx_buf);
1572e5b75505Sopenharmony_ci			wpabuf_put_le16(tx_buf, wpabuf_len(buf));
1573e5b75505Sopenharmony_ci			wpabuf_put_buf(tx_buf, buf);
1574e5b75505Sopenharmony_ci			hostapd_dpp_gas_status_handler(hapd, 1);
1575e5b75505Sopenharmony_ci		}
1576e5b75505Sopenharmony_ci		wpabuf_free(buf);
1577e5b75505Sopenharmony_ci	}
1578e5b75505Sopenharmony_ci	if (!tx_buf)
1579e5b75505Sopenharmony_ci		return;
1580e5b75505Sopenharmony_ci	if (prot)
1581e5b75505Sopenharmony_ci		convert_to_protected_dual(tx_buf);
1582e5b75505Sopenharmony_ci	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
1583e5b75505Sopenharmony_ci				wpabuf_head(tx_buf),
1584e5b75505Sopenharmony_ci				wpabuf_len(tx_buf));
1585e5b75505Sopenharmony_ci	wpabuf_free(tx_buf);
1586e5b75505Sopenharmony_ci}
1587e5b75505Sopenharmony_ci#endif /* CONFIG_DPP */
1588e5b75505Sopenharmony_ci
1589e5b75505Sopenharmony_ci
1590e5b75505Sopenharmony_cistatic void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
1591e5b75505Sopenharmony_ci					const u8 *sa,
1592e5b75505Sopenharmony_ci					const u8 *data, size_t len, int prot,
1593e5b75505Sopenharmony_ci					int std_addr3)
1594e5b75505Sopenharmony_ci{
1595e5b75505Sopenharmony_ci	const u8 *pos = data;
1596e5b75505Sopenharmony_ci	const u8 *end = data + len;
1597e5b75505Sopenharmony_ci	const u8 *next;
1598e5b75505Sopenharmony_ci	u8 dialog_token;
1599e5b75505Sopenharmony_ci	u16 slen;
1600e5b75505Sopenharmony_ci	struct anqp_query_info qi;
1601e5b75505Sopenharmony_ci	const u8 *adv_proto;
1602e5b75505Sopenharmony_ci#ifdef CONFIG_DPP
1603e5b75505Sopenharmony_ci	int dpp = 0;
1604e5b75505Sopenharmony_ci#endif /* CONFIG_DPP */
1605e5b75505Sopenharmony_ci
1606e5b75505Sopenharmony_ci	if (len < 1 + 2)
1607e5b75505Sopenharmony_ci		return;
1608e5b75505Sopenharmony_ci
1609e5b75505Sopenharmony_ci	os_memset(&qi, 0, sizeof(qi));
1610e5b75505Sopenharmony_ci
1611e5b75505Sopenharmony_ci	dialog_token = *pos++;
1612e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_DEBUG,
1613e5b75505Sopenharmony_ci		"GAS: GAS Initial Request from " MACSTR " (dialog token %u) ",
1614e5b75505Sopenharmony_ci		MAC2STR(sa), dialog_token);
1615e5b75505Sopenharmony_ci
1616e5b75505Sopenharmony_ci	if (*pos != WLAN_EID_ADV_PROTO) {
1617e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
1618e5b75505Sopenharmony_ci			"GAS: Unexpected IE in GAS Initial Request: %u", *pos);
1619e5b75505Sopenharmony_ci		return;
1620e5b75505Sopenharmony_ci	}
1621e5b75505Sopenharmony_ci	adv_proto = pos++;
1622e5b75505Sopenharmony_ci
1623e5b75505Sopenharmony_ci	slen = *pos++;
1624e5b75505Sopenharmony_ci	if (slen > end - pos || slen < 2) {
1625e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
1626e5b75505Sopenharmony_ci			"GAS: Invalid IE in GAS Initial Request");
1627e5b75505Sopenharmony_ci		return;
1628e5b75505Sopenharmony_ci	}
1629e5b75505Sopenharmony_ci	next = pos + slen;
1630e5b75505Sopenharmony_ci	pos++; /* skip QueryRespLenLimit and PAME-BI */
1631e5b75505Sopenharmony_ci
1632e5b75505Sopenharmony_ci#ifdef CONFIG_DPP
1633e5b75505Sopenharmony_ci	if (slen == 8 && *pos == WLAN_EID_VENDOR_SPECIFIC &&
1634e5b75505Sopenharmony_ci	    pos[1] == 5 && WPA_GET_BE24(&pos[2]) == OUI_WFA &&
1635e5b75505Sopenharmony_ci	    pos[5] == DPP_OUI_TYPE && pos[6] == 0x01) {
1636e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Configuration Request");
1637e5b75505Sopenharmony_ci		dpp = 1;
1638e5b75505Sopenharmony_ci	} else
1639e5b75505Sopenharmony_ci#endif /* CONFIG_DPP */
1640e5b75505Sopenharmony_ci
1641e5b75505Sopenharmony_ci	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
1642e5b75505Sopenharmony_ci		struct wpabuf *buf;
1643e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
1644e5b75505Sopenharmony_ci			"GAS: Unsupported GAS advertisement protocol id %u",
1645e5b75505Sopenharmony_ci			*pos);
1646e5b75505Sopenharmony_ci		if (sa[0] & 0x01)
1647e5b75505Sopenharmony_ci			return; /* Invalid source address - drop silently */
1648e5b75505Sopenharmony_ci		buf = gas_build_initial_resp(
1649e5b75505Sopenharmony_ci			dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED,
1650e5b75505Sopenharmony_ci			0, 2 + slen + 2);
1651e5b75505Sopenharmony_ci		if (buf == NULL)
1652e5b75505Sopenharmony_ci			return;
1653e5b75505Sopenharmony_ci		wpabuf_put_data(buf, adv_proto, 2 + slen);
1654e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, 0); /* Query Response Length */
1655e5b75505Sopenharmony_ci		if (prot)
1656e5b75505Sopenharmony_ci			convert_to_protected_dual(buf);
1657e5b75505Sopenharmony_ci		if (std_addr3)
1658e5b75505Sopenharmony_ci			hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
1659e5b75505Sopenharmony_ci						wpabuf_head(buf),
1660e5b75505Sopenharmony_ci						wpabuf_len(buf));
1661e5b75505Sopenharmony_ci		else
1662e5b75505Sopenharmony_ci			hostapd_drv_send_action_addr3_ap(hapd,
1663e5b75505Sopenharmony_ci							 hapd->iface->freq, 0,
1664e5b75505Sopenharmony_ci							 sa, wpabuf_head(buf),
1665e5b75505Sopenharmony_ci							 wpabuf_len(buf));
1666e5b75505Sopenharmony_ci		wpabuf_free(buf);
1667e5b75505Sopenharmony_ci		return;
1668e5b75505Sopenharmony_ci	}
1669e5b75505Sopenharmony_ci
1670e5b75505Sopenharmony_ci	pos = next;
1671e5b75505Sopenharmony_ci	/* Query Request */
1672e5b75505Sopenharmony_ci	if (end - pos < 2)
1673e5b75505Sopenharmony_ci		return;
1674e5b75505Sopenharmony_ci	slen = WPA_GET_LE16(pos);
1675e5b75505Sopenharmony_ci	pos += 2;
1676e5b75505Sopenharmony_ci	if (slen > end - pos)
1677e5b75505Sopenharmony_ci		return;
1678e5b75505Sopenharmony_ci	end = pos + slen;
1679e5b75505Sopenharmony_ci
1680e5b75505Sopenharmony_ci#ifdef CONFIG_DPP
1681e5b75505Sopenharmony_ci	if (dpp) {
1682e5b75505Sopenharmony_ci		struct wpabuf *msg;
1683e5b75505Sopenharmony_ci
1684e5b75505Sopenharmony_ci		msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen,
1685e5b75505Sopenharmony_ci						  data, len);
1686e5b75505Sopenharmony_ci		if (!msg)
1687e5b75505Sopenharmony_ci			return;
1688e5b75505Sopenharmony_ci		gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg);
1689e5b75505Sopenharmony_ci		return;
1690e5b75505Sopenharmony_ci	}
1691e5b75505Sopenharmony_ci#endif /* CONFIG_DPP */
1692e5b75505Sopenharmony_ci
1693e5b75505Sopenharmony_ci	/* ANQP Query Request */
1694e5b75505Sopenharmony_ci	while (pos < end) {
1695e5b75505Sopenharmony_ci		u16 info_id, elen;
1696e5b75505Sopenharmony_ci
1697e5b75505Sopenharmony_ci		if (end - pos < 4)
1698e5b75505Sopenharmony_ci			return;
1699e5b75505Sopenharmony_ci
1700e5b75505Sopenharmony_ci		info_id = WPA_GET_LE16(pos);
1701e5b75505Sopenharmony_ci		pos += 2;
1702e5b75505Sopenharmony_ci		elen = WPA_GET_LE16(pos);
1703e5b75505Sopenharmony_ci		pos += 2;
1704e5b75505Sopenharmony_ci
1705e5b75505Sopenharmony_ci		if (elen > end - pos) {
1706e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
1707e5b75505Sopenharmony_ci			return;
1708e5b75505Sopenharmony_ci		}
1709e5b75505Sopenharmony_ci
1710e5b75505Sopenharmony_ci		switch (info_id) {
1711e5b75505Sopenharmony_ci		case ANQP_QUERY_LIST:
1712e5b75505Sopenharmony_ci			rx_anqp_query_list(hapd, pos, pos + elen, &qi);
1713e5b75505Sopenharmony_ci			break;
1714e5b75505Sopenharmony_ci		case ANQP_VENDOR_SPECIFIC:
1715e5b75505Sopenharmony_ci			rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi);
1716e5b75505Sopenharmony_ci			break;
1717e5b75505Sopenharmony_ci		default:
1718e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
1719e5b75505Sopenharmony_ci				   "Request element %u", info_id);
1720e5b75505Sopenharmony_ci			break;
1721e5b75505Sopenharmony_ci		}
1722e5b75505Sopenharmony_ci
1723e5b75505Sopenharmony_ci		pos += elen;
1724e5b75505Sopenharmony_ci	}
1725e5b75505Sopenharmony_ci
1726e5b75505Sopenharmony_ci	gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot,
1727e5b75505Sopenharmony_ci				      std_addr3);
1728e5b75505Sopenharmony_ci}
1729e5b75505Sopenharmony_ci
1730e5b75505Sopenharmony_ci
1731e5b75505Sopenharmony_cistatic void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
1732e5b75505Sopenharmony_ci					 const u8 *sa,
1733e5b75505Sopenharmony_ci					 const u8 *data, size_t len, int prot,
1734e5b75505Sopenharmony_ci					 int std_addr3)
1735e5b75505Sopenharmony_ci{
1736e5b75505Sopenharmony_ci	struct gas_dialog_info *dialog;
1737e5b75505Sopenharmony_ci	struct wpabuf *buf, *tx_buf;
1738e5b75505Sopenharmony_ci	u8 dialog_token;
1739e5b75505Sopenharmony_ci	size_t frag_len;
1740e5b75505Sopenharmony_ci	int more = 0;
1741e5b75505Sopenharmony_ci
1742e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len);
1743e5b75505Sopenharmony_ci	if (len < 1)
1744e5b75505Sopenharmony_ci		return;
1745e5b75505Sopenharmony_ci	dialog_token = *data;
1746e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u",
1747e5b75505Sopenharmony_ci		dialog_token);
1748e5b75505Sopenharmony_ci
1749e5b75505Sopenharmony_ci	dialog = gas_serv_dialog_find(hapd, sa, dialog_token);
1750e5b75505Sopenharmony_ci	if (!dialog) {
1751e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD "
1752e5b75505Sopenharmony_ci			"response fragment for " MACSTR " dialog token %u",
1753e5b75505Sopenharmony_ci			MAC2STR(sa), dialog_token);
1754e5b75505Sopenharmony_ci
1755e5b75505Sopenharmony_ci		if (sa[0] & 0x01)
1756e5b75505Sopenharmony_ci			return; /* Invalid source address - drop silently */
1757e5b75505Sopenharmony_ci		tx_buf = gas_anqp_build_comeback_resp_buf(
1758e5b75505Sopenharmony_ci			dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0,
1759e5b75505Sopenharmony_ci			0, NULL);
1760e5b75505Sopenharmony_ci		if (tx_buf == NULL)
1761e5b75505Sopenharmony_ci			return;
1762e5b75505Sopenharmony_ci		goto send_resp;
1763e5b75505Sopenharmony_ci	}
1764e5b75505Sopenharmony_ci
1765e5b75505Sopenharmony_ci	frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
1766e5b75505Sopenharmony_ci	if (frag_len > hapd->conf->gas_frag_limit) {
1767e5b75505Sopenharmony_ci		frag_len = hapd->conf->gas_frag_limit;
1768e5b75505Sopenharmony_ci		more = 1;
1769e5b75505Sopenharmony_ci	}
1770e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
1771e5b75505Sopenharmony_ci		(unsigned int) frag_len);
1772e5b75505Sopenharmony_ci	buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
1773e5b75505Sopenharmony_ci				dialog->sd_resp_pos, frag_len);
1774e5b75505Sopenharmony_ci	if (buf == NULL) {
1775e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
1776e5b75505Sopenharmony_ci			"buffer");
1777e5b75505Sopenharmony_ci		gas_serv_dialog_clear(dialog);
1778e5b75505Sopenharmony_ci		return;
1779e5b75505Sopenharmony_ci	}
1780e5b75505Sopenharmony_ci#ifdef CONFIG_DPP
1781e5b75505Sopenharmony_ci	if (dialog->dpp) {
1782e5b75505Sopenharmony_ci		tx_buf = gas_build_comeback_resp(dialog_token,
1783e5b75505Sopenharmony_ci						 WLAN_STATUS_SUCCESS,
1784e5b75505Sopenharmony_ci						 dialog->sd_frag_id, more, 0,
1785e5b75505Sopenharmony_ci						 10 + frag_len);
1786e5b75505Sopenharmony_ci		if (tx_buf) {
1787e5b75505Sopenharmony_ci			gas_serv_write_dpp_adv_proto(tx_buf);
1788e5b75505Sopenharmony_ci			wpabuf_put_buf(tx_buf, buf);
1789e5b75505Sopenharmony_ci		}
1790e5b75505Sopenharmony_ci	} else
1791e5b75505Sopenharmony_ci#endif /* CONFIG_DPP */
1792e5b75505Sopenharmony_ci	tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
1793e5b75505Sopenharmony_ci						  WLAN_STATUS_SUCCESS,
1794e5b75505Sopenharmony_ci						  dialog->sd_frag_id,
1795e5b75505Sopenharmony_ci						  more, 0, buf);
1796e5b75505Sopenharmony_ci	wpabuf_free(buf);
1797e5b75505Sopenharmony_ci	if (tx_buf == NULL) {
1798e5b75505Sopenharmony_ci		gas_serv_dialog_clear(dialog);
1799e5b75505Sopenharmony_ci		return;
1800e5b75505Sopenharmony_ci	}
1801e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
1802e5b75505Sopenharmony_ci		"(frag_id %d more=%d frag_len=%d)",
1803e5b75505Sopenharmony_ci		dialog->sd_frag_id, more, (int) frag_len);
1804e5b75505Sopenharmony_ci	dialog->sd_frag_id++;
1805e5b75505Sopenharmony_ci	dialog->sd_resp_pos += frag_len;
1806e5b75505Sopenharmony_ci
1807e5b75505Sopenharmony_ci	if (more) {
1808e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain "
1809e5b75505Sopenharmony_ci			"to be sent",
1810e5b75505Sopenharmony_ci			(int) (wpabuf_len(dialog->sd_resp) -
1811e5b75505Sopenharmony_ci			       dialog->sd_resp_pos));
1812e5b75505Sopenharmony_ci	} else {
1813e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
1814e5b75505Sopenharmony_ci			"SD response sent");
1815e5b75505Sopenharmony_ci#ifdef CONFIG_DPP
1816e5b75505Sopenharmony_ci		if (dialog->dpp)
1817e5b75505Sopenharmony_ci			hostapd_dpp_gas_status_handler(hapd, 1);
1818e5b75505Sopenharmony_ci#endif /* CONFIG_DPP */
1819e5b75505Sopenharmony_ci		gas_serv_dialog_clear(dialog);
1820e5b75505Sopenharmony_ci		gas_serv_free_dialogs(hapd, sa);
1821e5b75505Sopenharmony_ci	}
1822e5b75505Sopenharmony_ci
1823e5b75505Sopenharmony_cisend_resp:
1824e5b75505Sopenharmony_ci	if (prot)
1825e5b75505Sopenharmony_ci		convert_to_protected_dual(tx_buf);
1826e5b75505Sopenharmony_ci	if (std_addr3)
1827e5b75505Sopenharmony_ci		hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
1828e5b75505Sopenharmony_ci					wpabuf_head(tx_buf),
1829e5b75505Sopenharmony_ci					wpabuf_len(tx_buf));
1830e5b75505Sopenharmony_ci	else
1831e5b75505Sopenharmony_ci		hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
1832e5b75505Sopenharmony_ci						 wpabuf_head(tx_buf),
1833e5b75505Sopenharmony_ci						 wpabuf_len(tx_buf));
1834e5b75505Sopenharmony_ci	wpabuf_free(tx_buf);
1835e5b75505Sopenharmony_ci}
1836e5b75505Sopenharmony_ci
1837e5b75505Sopenharmony_ci
1838e5b75505Sopenharmony_cistatic void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
1839e5b75505Sopenharmony_ci				      int freq)
1840e5b75505Sopenharmony_ci{
1841e5b75505Sopenharmony_ci	struct hostapd_data *hapd = ctx;
1842e5b75505Sopenharmony_ci	const struct ieee80211_mgmt *mgmt;
1843e5b75505Sopenharmony_ci	const u8 *sa, *data;
1844e5b75505Sopenharmony_ci	int prot, std_addr3;
1845e5b75505Sopenharmony_ci
1846e5b75505Sopenharmony_ci	mgmt = (const struct ieee80211_mgmt *) buf;
1847e5b75505Sopenharmony_ci	if (len < IEEE80211_HDRLEN + 2)
1848e5b75505Sopenharmony_ci		return;
1849e5b75505Sopenharmony_ci	if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
1850e5b75505Sopenharmony_ci	    mgmt->u.action.category != WLAN_ACTION_PROTECTED_DUAL)
1851e5b75505Sopenharmony_ci		return;
1852e5b75505Sopenharmony_ci	/*
1853e5b75505Sopenharmony_ci	 * Note: Public Action and Protected Dual of Public Action frames share
1854e5b75505Sopenharmony_ci	 * the same payload structure, so it is fine to use definitions of
1855e5b75505Sopenharmony_ci	 * Public Action frames to process both.
1856e5b75505Sopenharmony_ci	 */
1857e5b75505Sopenharmony_ci	prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
1858e5b75505Sopenharmony_ci	sa = mgmt->sa;
1859e5b75505Sopenharmony_ci	if (hapd->conf->gas_address3 == 1)
1860e5b75505Sopenharmony_ci		std_addr3 = 1;
1861e5b75505Sopenharmony_ci	else if (hapd->conf->gas_address3 == 2)
1862e5b75505Sopenharmony_ci		std_addr3 = 0;
1863e5b75505Sopenharmony_ci	else
1864e5b75505Sopenharmony_ci		std_addr3 = is_broadcast_ether_addr(mgmt->bssid);
1865e5b75505Sopenharmony_ci	len -= IEEE80211_HDRLEN + 1;
1866e5b75505Sopenharmony_ci	data = buf + IEEE80211_HDRLEN + 1;
1867e5b75505Sopenharmony_ci	switch (data[0]) {
1868e5b75505Sopenharmony_ci	case WLAN_PA_GAS_INITIAL_REQ:
1869e5b75505Sopenharmony_ci		gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot,
1870e5b75505Sopenharmony_ci					    std_addr3);
1871e5b75505Sopenharmony_ci		break;
1872e5b75505Sopenharmony_ci	case WLAN_PA_GAS_COMEBACK_REQ:
1873e5b75505Sopenharmony_ci		gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot,
1874e5b75505Sopenharmony_ci					     std_addr3);
1875e5b75505Sopenharmony_ci		break;
1876e5b75505Sopenharmony_ci	}
1877e5b75505Sopenharmony_ci}
1878e5b75505Sopenharmony_ci
1879e5b75505Sopenharmony_ci
1880e5b75505Sopenharmony_ciint gas_serv_init(struct hostapd_data *hapd)
1881e5b75505Sopenharmony_ci{
1882e5b75505Sopenharmony_ci	hapd->public_action_cb2 = gas_serv_rx_public_action;
1883e5b75505Sopenharmony_ci	hapd->public_action_cb2_ctx = hapd;
1884e5b75505Sopenharmony_ci	return 0;
1885e5b75505Sopenharmony_ci}
1886e5b75505Sopenharmony_ci
1887e5b75505Sopenharmony_ci
1888e5b75505Sopenharmony_civoid gas_serv_deinit(struct hostapd_data *hapd)
1889e5b75505Sopenharmony_ci{
1890e5b75505Sopenharmony_ci}
1891