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