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