gas_serv.c revision 5460547a121207cf7a99eac45e05fcdd83be3161
1/*
2 * Generic advertisement service (GAS) server
3 * Copyright (c) 2011-2012, 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 "utils/eloop.h"
15#include "hostapd.h"
16#include "ap_config.h"
17#include "ap_drv_ops.h"
18#include "sta_info.h"
19#include "gas_serv.h"
20
21
22static struct gas_dialog_info *
23gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
24{
25	struct sta_info *sta;
26	struct gas_dialog_info *dia = NULL;
27	int i, j;
28
29	sta = ap_get_sta(hapd, addr);
30	if (!sta) {
31		/*
32		 * We need a STA entry to be able to maintain state for
33		 * the GAS query.
34		 */
35		wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for "
36			   "GAS query");
37		sta = ap_sta_add(hapd, addr);
38		if (!sta) {
39			wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR
40				   " for GAS query", MAC2STR(addr));
41			return NULL;
42		}
43		sta->flags |= WLAN_STA_GAS;
44		/*
45		 * The default inactivity is 300 seconds. We don't need
46		 * it to be that long.
47		 */
48		ap_sta_session_timeout(hapd, sta, 5);
49	} else {
50		ap_sta_replenish_timeout(hapd, sta, 5);
51	}
52
53	if (sta->gas_dialog == NULL) {
54		sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX *
55					    sizeof(struct gas_dialog_info));
56		if (sta->gas_dialog == NULL)
57			return NULL;
58	}
59
60	for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) {
61		if (i == GAS_DIALOG_MAX)
62			i = 0;
63		if (sta->gas_dialog[i].valid)
64			continue;
65		dia = &sta->gas_dialog[i];
66		dia->valid = 1;
67		dia->index = i;
68		dia->dialog_token = dialog_token;
69		sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i;
70		return dia;
71	}
72
73	wpa_msg(hapd->msg_ctx, MSG_ERROR, "ANQP: Could not create dialog for "
74		MACSTR " dialog_token %u. Consider increasing "
75		"GAS_DIALOG_MAX.", MAC2STR(addr), dialog_token);
76
77	return NULL;
78}
79
80
81struct gas_dialog_info *
82gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
83		     u8 dialog_token)
84{
85	struct sta_info *sta;
86	int i;
87
88	sta = ap_get_sta(hapd, addr);
89	if (!sta) {
90		wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR,
91			   MAC2STR(addr));
92		return NULL;
93	}
94	for (i = 0; sta->gas_dialog && i < GAS_DIALOG_MAX; i++) {
95		if (sta->gas_dialog[i].dialog_token != dialog_token ||
96		    !sta->gas_dialog[i].valid)
97			continue;
98		return &sta->gas_dialog[i];
99	}
100	wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
101		   MACSTR " dialog_token %u", MAC2STR(addr), dialog_token);
102	return NULL;
103}
104
105
106void gas_serv_dialog_clear(struct gas_dialog_info *dia)
107{
108	wpabuf_free(dia->sd_resp);
109	os_memset(dia, 0, sizeof(*dia));
110}
111
112
113static void gas_serv_free_dialogs(struct hostapd_data *hapd,
114				  const u8 *sta_addr)
115{
116	struct sta_info *sta;
117	int i;
118
119	sta = ap_get_sta(hapd, sta_addr);
120	if (sta == NULL || sta->gas_dialog == NULL)
121		return;
122
123	for (i = 0; i < GAS_DIALOG_MAX; i++) {
124		if (sta->gas_dialog[i].valid)
125			return;
126	}
127
128	os_free(sta->gas_dialog);
129	sta->gas_dialog = NULL;
130}
131
132
133#ifdef CONFIG_HS20
134static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
135				   struct wpabuf *buf)
136{
137	u8 *len;
138
139	len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
140	wpabuf_put_be24(buf, OUI_WFA);
141	wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
142	wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
143	wpabuf_put_u8(buf, 0); /* Reserved */
144	wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
145	if (hapd->conf->hs20_oper_friendly_name)
146		wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
147	if (hapd->conf->hs20_wan_metrics)
148		wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
149	if (hapd->conf->hs20_connection_capability)
150		wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
151	if (hapd->conf->nai_realm_data)
152		wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
153	if (hapd->conf->hs20_operating_class)
154		wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
155	gas_anqp_set_element_len(buf, len);
156}
157#endif /* CONFIG_HS20 */
158
159
160static void anqp_add_capab_list(struct hostapd_data *hapd,
161				struct wpabuf *buf)
162{
163	u8 *len;
164
165	len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
166	wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
167	if (hapd->conf->venue_name)
168		wpabuf_put_le16(buf, ANQP_VENUE_NAME);
169	if (hapd->conf->network_auth_type)
170		wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
171	if (hapd->conf->roaming_consortium)
172		wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
173	if (hapd->conf->ipaddr_type_configured)
174		wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
175	if (hapd->conf->nai_realm_data)
176		wpabuf_put_le16(buf, ANQP_NAI_REALM);
177	if (hapd->conf->anqp_3gpp_cell_net)
178		wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
179	if (hapd->conf->domain_name)
180		wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
181#ifdef CONFIG_HS20
182	anqp_add_hs_capab_list(hapd, buf);
183#endif /* CONFIG_HS20 */
184	gas_anqp_set_element_len(buf, len);
185}
186
187
188static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
189{
190	if (hapd->conf->venue_name) {
191		u8 *len;
192		unsigned int i;
193		len = gas_anqp_add_element(buf, ANQP_VENUE_NAME);
194		wpabuf_put_u8(buf, hapd->conf->venue_group);
195		wpabuf_put_u8(buf, hapd->conf->venue_type);
196		for (i = 0; i < hapd->conf->venue_name_count; i++) {
197			struct hostapd_lang_string *vn;
198			vn = &hapd->conf->venue_name[i];
199			wpabuf_put_u8(buf, 3 + vn->name_len);
200			wpabuf_put_data(buf, vn->lang, 3);
201			wpabuf_put_data(buf, vn->name, vn->name_len);
202		}
203		gas_anqp_set_element_len(buf, len);
204	}
205}
206
207
208static void anqp_add_network_auth_type(struct hostapd_data *hapd,
209				       struct wpabuf *buf)
210{
211	if (hapd->conf->network_auth_type) {
212		wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
213		wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
214		wpabuf_put_data(buf, hapd->conf->network_auth_type,
215				hapd->conf->network_auth_type_len);
216	}
217}
218
219
220static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
221					struct wpabuf *buf)
222{
223	unsigned int i;
224	u8 *len;
225
226	len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
227	for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
228		struct hostapd_roaming_consortium *rc;
229		rc = &hapd->conf->roaming_consortium[i];
230		wpabuf_put_u8(buf, rc->len);
231		wpabuf_put_data(buf, rc->oi, rc->len);
232	}
233	gas_anqp_set_element_len(buf, len);
234}
235
236
237static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
238					       struct wpabuf *buf)
239{
240	if (hapd->conf->ipaddr_type_configured) {
241		wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
242		wpabuf_put_le16(buf, 1);
243		wpabuf_put_u8(buf, hapd->conf->ipaddr_type_availability);
244	}
245}
246
247
248static void anqp_add_nai_realm_eap(struct wpabuf *buf,
249				   struct hostapd_nai_realm_data *realm)
250{
251	unsigned int i, j;
252
253	wpabuf_put_u8(buf, realm->eap_method_count);
254
255	for (i = 0; i < realm->eap_method_count; i++) {
256		struct hostapd_nai_realm_eap *eap = &realm->eap_method[i];
257		wpabuf_put_u8(buf, 2 + (3 * eap->num_auths));
258		wpabuf_put_u8(buf, eap->eap_method);
259		wpabuf_put_u8(buf, eap->num_auths);
260		for (j = 0; j < eap->num_auths; j++) {
261			wpabuf_put_u8(buf, eap->auth_id[j]);
262			wpabuf_put_u8(buf, 1);
263			wpabuf_put_u8(buf, eap->auth_val[j]);
264		}
265	}
266}
267
268
269static void anqp_add_nai_realm_data(struct wpabuf *buf,
270				    struct hostapd_nai_realm_data *realm,
271				    unsigned int realm_idx)
272{
273	u8 *realm_data_len;
274
275	wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx],
276		   (int) os_strlen(realm->realm[realm_idx]));
277	realm_data_len = wpabuf_put(buf, 2);
278	wpabuf_put_u8(buf, realm->encoding);
279	wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx]));
280	wpabuf_put_str(buf, realm->realm[realm_idx]);
281	anqp_add_nai_realm_eap(buf, realm);
282	gas_anqp_set_element_len(buf, realm_data_len);
283}
284
285
286static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
287					   struct wpabuf *buf,
288					   const u8 *home_realm,
289					   size_t home_realm_len)
290{
291	unsigned int i, j, k;
292	u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len;
293	struct hostapd_nai_realm_data *realm;
294	const u8 *pos, *realm_name, *end;
295	struct {
296		unsigned int realm_data_idx;
297		unsigned int realm_idx;
298	} matches[10];
299
300	pos = home_realm;
301	end = pos + home_realm_len;
302	if (pos + 1 > end) {
303		wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
304			    home_realm, home_realm_len);
305		return -1;
306	}
307	num_realms = *pos++;
308
309	for (i = 0; i < num_realms && num_matching < 10; i++) {
310		if (pos + 2 > end) {
311			wpa_hexdump(MSG_DEBUG,
312				    "Truncated NAI Home Realm Query",
313				    home_realm, home_realm_len);
314			return -1;
315		}
316		encoding = *pos++;
317		realm_len = *pos++;
318		if (pos + realm_len > end) {
319			wpa_hexdump(MSG_DEBUG,
320				    "Truncated NAI Home Realm Query",
321				    home_realm, home_realm_len);
322			return -1;
323		}
324		realm_name = pos;
325		for (j = 0; j < hapd->conf->nai_realm_count &&
326			     num_matching < 10; j++) {
327			const u8 *rpos, *rend;
328			realm = &hapd->conf->nai_realm_data[j];
329			if (encoding != realm->encoding)
330				continue;
331
332			rpos = realm_name;
333			while (rpos < realm_name + realm_len &&
334			       num_matching < 10) {
335				for (rend = rpos;
336				     rend < realm_name + realm_len; rend++) {
337					if (*rend == ';')
338						break;
339				}
340				for (k = 0; k < MAX_NAI_REALMS &&
341					     realm->realm[k] &&
342					     num_matching < 10; k++) {
343					if ((int) os_strlen(realm->realm[k]) !=
344					    rend - rpos ||
345					    os_strncmp((char *) rpos,
346						       realm->realm[k],
347						       rend - rpos) != 0)
348						continue;
349					matches[num_matching].realm_data_idx =
350						j;
351					matches[num_matching].realm_idx = k;
352					num_matching++;
353				}
354				rpos = rend + 1;
355			}
356		}
357		pos += realm_len;
358	}
359
360	realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
361	wpabuf_put_le16(buf, num_matching);
362
363	/*
364	 * There are two ways to format. 1. each realm in a NAI Realm Data unit
365	 * 2. all realms that share the same EAP methods in a NAI Realm Data
366	 * unit. The first format is likely to be bigger in size than the
367	 * second, but may be easier to parse and process by the receiver.
368	 */
369	for (i = 0; i < num_matching; i++) {
370		wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d",
371			   matches[i].realm_data_idx, matches[i].realm_idx);
372		realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx];
373		anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx);
374	}
375	gas_anqp_set_element_len(buf, realm_list_len);
376	return 0;
377}
378
379
380static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
381			       const u8 *home_realm, size_t home_realm_len,
382			       int nai_realm, int nai_home_realm)
383{
384	if (nai_realm && hapd->conf->nai_realm_data) {
385		u8 *len;
386		unsigned int i, j;
387		len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
388		wpabuf_put_le16(buf, hapd->conf->nai_realm_count);
389		for (i = 0; i < hapd->conf->nai_realm_count; i++) {
390			u8 *realm_data_len, *realm_len;
391			struct hostapd_nai_realm_data *realm;
392
393			realm = &hapd->conf->nai_realm_data[i];
394			realm_data_len = wpabuf_put(buf, 2);
395			wpabuf_put_u8(buf, realm->encoding);
396			realm_len = wpabuf_put(buf, 1);
397			for (j = 0; realm->realm[j]; j++) {
398				if (j > 0)
399					wpabuf_put_u8(buf, ';');
400				wpabuf_put_str(buf, realm->realm[j]);
401			}
402			*realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1;
403			anqp_add_nai_realm_eap(buf, realm);
404			gas_anqp_set_element_len(buf, realm_data_len);
405		}
406		gas_anqp_set_element_len(buf, len);
407	} else if (nai_home_realm && hapd->conf->nai_realm_data) {
408		hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
409						home_realm_len);
410	}
411}
412
413
414static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
415					   struct wpabuf *buf)
416{
417	if (hapd->conf->anqp_3gpp_cell_net) {
418		wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
419		wpabuf_put_le16(buf,
420				hapd->conf->anqp_3gpp_cell_net_len);
421		wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net,
422				hapd->conf->anqp_3gpp_cell_net_len);
423	}
424}
425
426
427static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
428{
429	if (hapd->conf->domain_name) {
430		wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
431		wpabuf_put_le16(buf, hapd->conf->domain_name_len);
432		wpabuf_put_data(buf, hapd->conf->domain_name,
433				hapd->conf->domain_name_len);
434	}
435}
436
437
438#ifdef CONFIG_HS20
439
440static void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
441					    struct wpabuf *buf)
442{
443	if (hapd->conf->hs20_oper_friendly_name) {
444		u8 *len;
445		unsigned int i;
446		len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
447		wpabuf_put_be24(buf, OUI_WFA);
448		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
449		wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
450		wpabuf_put_u8(buf, 0); /* Reserved */
451		for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++)
452		{
453			struct hostapd_lang_string *vn;
454			vn = &hapd->conf->hs20_oper_friendly_name[i];
455			wpabuf_put_u8(buf, 3 + vn->name_len);
456			wpabuf_put_data(buf, vn->lang, 3);
457			wpabuf_put_data(buf, vn->name, vn->name_len);
458		}
459		gas_anqp_set_element_len(buf, len);
460	}
461}
462
463
464static void anqp_add_wan_metrics(struct hostapd_data *hapd,
465				 struct wpabuf *buf)
466{
467	if (hapd->conf->hs20_wan_metrics) {
468		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
469		wpabuf_put_be24(buf, OUI_WFA);
470		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
471		wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
472		wpabuf_put_u8(buf, 0); /* Reserved */
473		wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13);
474		gas_anqp_set_element_len(buf, len);
475	}
476}
477
478
479static void anqp_add_connection_capability(struct hostapd_data *hapd,
480					   struct wpabuf *buf)
481{
482	if (hapd->conf->hs20_connection_capability) {
483		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
484		wpabuf_put_be24(buf, OUI_WFA);
485		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
486		wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
487		wpabuf_put_u8(buf, 0); /* Reserved */
488		wpabuf_put_data(buf, hapd->conf->hs20_connection_capability,
489				hapd->conf->hs20_connection_capability_len);
490		gas_anqp_set_element_len(buf, len);
491	}
492}
493
494
495static void anqp_add_operating_class(struct hostapd_data *hapd,
496				     struct wpabuf *buf)
497{
498	if (hapd->conf->hs20_operating_class) {
499		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
500		wpabuf_put_be24(buf, OUI_WFA);
501		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
502		wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
503		wpabuf_put_u8(buf, 0); /* Reserved */
504		wpabuf_put_data(buf, hapd->conf->hs20_operating_class,
505				hapd->conf->hs20_operating_class_len);
506		gas_anqp_set_element_len(buf, len);
507	}
508}
509
510#endif /* CONFIG_HS20 */
511
512
513static struct wpabuf *
514gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
515				unsigned int request,
516				struct gas_dialog_info *di,
517				const u8 *home_realm, size_t home_realm_len)
518{
519	struct wpabuf *buf;
520
521	buf = wpabuf_alloc(1400);
522	if (buf == NULL)
523		return NULL;
524
525	if (request & ANQP_REQ_CAPABILITY_LIST)
526		anqp_add_capab_list(hapd, buf);
527	if (request & ANQP_REQ_VENUE_NAME)
528		anqp_add_venue_name(hapd, buf);
529	if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
530		anqp_add_network_auth_type(hapd, buf);
531	if (request & ANQP_REQ_ROAMING_CONSORTIUM)
532		anqp_add_roaming_consortium(hapd, buf);
533	if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY)
534		anqp_add_ip_addr_type_availability(hapd, buf);
535	if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
536		anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len,
537				   request & ANQP_REQ_NAI_REALM,
538				   request & ANQP_REQ_NAI_HOME_REALM);
539	if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
540		anqp_add_3gpp_cellular_network(hapd, buf);
541	if (request & ANQP_REQ_DOMAIN_NAME)
542		anqp_add_domain_name(hapd, buf);
543
544#ifdef CONFIG_HS20
545	if (request & ANQP_REQ_HS_CAPABILITY_LIST)
546		anqp_add_hs_capab_list(hapd, buf);
547	if (request & ANQP_REQ_OPERATOR_FRIENDLY_NAME)
548		anqp_add_operator_friendly_name(hapd, buf);
549	if (request & ANQP_REQ_WAN_METRICS)
550		anqp_add_wan_metrics(hapd, buf);
551	if (request & ANQP_REQ_CONNECTION_CAPABILITY)
552		anqp_add_connection_capability(hapd, buf);
553	if (request & ANQP_REQ_OPERATING_CLASS)
554		anqp_add_operating_class(hapd, buf);
555#endif /* CONFIG_HS20 */
556
557	return buf;
558}
559
560
561static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx)
562{
563	struct gas_dialog_info *dia = eloop_data;
564
565	wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for "
566		   "dialog token %d", dia->dialog_token);
567
568	gas_serv_dialog_clear(dia);
569}
570
571
572struct anqp_query_info {
573	unsigned int request;
574	unsigned int remote_request;
575	const u8 *home_realm_query;
576	size_t home_realm_query_len;
577	u16 remote_delay;
578};
579
580
581static void set_anqp_req(unsigned int bit, const char *name, int local,
582			 unsigned int remote, u16 remote_delay,
583			 struct anqp_query_info *qi)
584{
585	qi->request |= bit;
586	if (local) {
587		wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name);
588	} else if (bit & remote) {
589		wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name);
590		qi->remote_request |= bit;
591		if (remote_delay > qi->remote_delay)
592			qi->remote_delay = remote_delay;
593	} else {
594		wpa_printf(MSG_DEBUG, "ANQP: %s not available", name);
595	}
596}
597
598
599static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
600				  struct anqp_query_info *qi)
601{
602	switch (info_id) {
603	case ANQP_CAPABILITY_LIST:
604		set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0,
605			     0, qi);
606		break;
607	case ANQP_VENUE_NAME:
608		set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
609			     hapd->conf->venue_name != NULL, 0, 0, qi);
610		break;
611	case ANQP_NETWORK_AUTH_TYPE:
612		set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
613			     hapd->conf->network_auth_type != NULL,
614			     0, 0, qi);
615		break;
616	case ANQP_ROAMING_CONSORTIUM:
617		set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
618			     hapd->conf->roaming_consortium != NULL, 0, 0, qi);
619		break;
620	case ANQP_IP_ADDR_TYPE_AVAILABILITY:
621		set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY,
622			     "IP Addr Type Availability",
623			     hapd->conf->ipaddr_type_configured,
624			     0, 0, qi);
625		break;
626	case ANQP_NAI_REALM:
627		set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm",
628			     hapd->conf->nai_realm_data != NULL,
629			     0, 0, qi);
630		break;
631	case ANQP_3GPP_CELLULAR_NETWORK:
632		set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
633			     "3GPP Cellular Network",
634			     hapd->conf->anqp_3gpp_cell_net != NULL,
635			     0, 0, qi);
636		break;
637	case ANQP_DOMAIN_NAME:
638		set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
639			     hapd->conf->domain_name != NULL,
640			     0, 0, qi);
641		break;
642	default:
643		wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
644			   info_id);
645		break;
646	}
647}
648
649
650static void rx_anqp_query_list(struct hostapd_data *hapd,
651			       const u8 *pos, const u8 *end,
652			       struct anqp_query_info *qi)
653{
654	wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
655		   (unsigned int) (end - pos) / 2);
656
657	while (pos + 2 <= end) {
658		rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
659		pos += 2;
660	}
661}
662
663
664#ifdef CONFIG_HS20
665
666static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
667				  struct anqp_query_info *qi)
668{
669	switch (subtype) {
670	case HS20_STYPE_CAPABILITY_LIST:
671		set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List",
672			     1, 0, 0, qi);
673		break;
674	case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
675		set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME,
676			     "Operator Friendly Name",
677			     hapd->conf->hs20_oper_friendly_name != NULL,
678			     0, 0, qi);
679		break;
680	case HS20_STYPE_WAN_METRICS:
681		set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics",
682			     hapd->conf->hs20_wan_metrics != NULL,
683			     0, 0, qi);
684		break;
685	case HS20_STYPE_CONNECTION_CAPABILITY:
686		set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY,
687			     "Connection Capability",
688			     hapd->conf->hs20_connection_capability != NULL,
689			     0, 0, qi);
690		break;
691	case HS20_STYPE_OPERATING_CLASS:
692		set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class",
693			     hapd->conf->hs20_operating_class != NULL,
694			     0, 0, qi);
695		break;
696	default:
697		wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
698			   subtype);
699		break;
700	}
701}
702
703
704static void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd,
705				      const u8 *pos, const u8 *end,
706				      struct anqp_query_info *qi)
707{
708	qi->request |= ANQP_REQ_NAI_HOME_REALM;
709	qi->home_realm_query = pos;
710	qi->home_realm_query_len = end - pos;
711	if (hapd->conf->nai_realm_data != NULL) {
712		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query "
713			   "(local)");
714	} else {
715		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not "
716			   "available");
717	}
718}
719
720
721static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
722				    const u8 *pos, const u8 *end,
723				    struct anqp_query_info *qi)
724{
725	u32 oui;
726	u8 subtype;
727
728	if (pos + 4 > end) {
729		wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
730			   "Query element");
731		return;
732	}
733
734	oui = WPA_GET_BE24(pos);
735	pos += 3;
736	if (oui != OUI_WFA) {
737		wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
738			   oui);
739		return;
740	}
741
742	if (*pos != HS20_ANQP_OUI_TYPE) {
743		wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
744			   *pos);
745		return;
746	}
747	pos++;
748
749	if (pos + 1 >= end)
750		return;
751
752	subtype = *pos++;
753	pos++; /* Reserved */
754	switch (subtype) {
755	case HS20_STYPE_QUERY_LIST:
756		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List");
757		while (pos < end) {
758			rx_anqp_hs_query_list(hapd, *pos, qi);
759			pos++;
760		}
761		break;
762	case HS20_STYPE_NAI_HOME_REALM_QUERY:
763		rx_anqp_hs_nai_home_realm(hapd, pos, end, qi);
764		break;
765	default:
766		wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype "
767			   "%u", subtype);
768		break;
769	}
770}
771
772#endif /* CONFIG_HS20 */
773
774
775static void gas_serv_req_local_processing(struct hostapd_data *hapd,
776					  const u8 *sa, u8 dialog_token,
777					  struct anqp_query_info *qi)
778{
779	struct wpabuf *buf, *tx_buf;
780
781	buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL,
782					      qi->home_realm_query,
783					      qi->home_realm_query_len);
784	wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
785			buf);
786	if (!buf)
787		return;
788
789	if (wpabuf_len(buf) > hapd->gas_frag_limit ||
790	    hapd->conf->gas_comeback_delay) {
791		struct gas_dialog_info *di;
792		u16 comeback_delay = 1;
793
794		if (hapd->conf->gas_comeback_delay) {
795			/* Testing - allow overriding of the delay value */
796			comeback_delay = hapd->conf->gas_comeback_delay;
797		}
798
799		wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in "
800			   "initial response - use GAS comeback");
801		di = gas_dialog_create(hapd, sa, dialog_token);
802		if (!di) {
803			wpa_printf(MSG_INFO, "ANQP: Could not create dialog "
804				   "for " MACSTR " (dialog token %u)",
805				   MAC2STR(sa), dialog_token);
806			wpabuf_free(buf);
807			return;
808		}
809		di->sd_resp = buf;
810		di->sd_resp_pos = 0;
811		tx_buf = gas_anqp_build_initial_resp_buf(
812			dialog_token, WLAN_STATUS_SUCCESS, comeback_delay,
813			NULL);
814	} else {
815		wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)");
816		tx_buf = gas_anqp_build_initial_resp_buf(
817			dialog_token, WLAN_STATUS_SUCCESS, 0, buf);
818		wpabuf_free(buf);
819	}
820	if (!tx_buf)
821		return;
822
823	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
824				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
825	wpabuf_free(tx_buf);
826}
827
828
829static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
830					const u8 *sa,
831					const u8 *data, size_t len)
832{
833	const u8 *pos = data;
834	const u8 *end = data + len;
835	const u8 *next;
836	u8 dialog_token;
837	u16 slen;
838	struct anqp_query_info qi;
839	const u8 *adv_proto;
840
841	if (len < 1 + 2)
842		return;
843
844	os_memset(&qi, 0, sizeof(qi));
845
846	dialog_token = *pos++;
847	wpa_msg(hapd->msg_ctx, MSG_DEBUG,
848		"GAS: GAS Initial Request from " MACSTR " (dialog token %u) ",
849		MAC2STR(sa), dialog_token);
850
851	if (*pos != WLAN_EID_ADV_PROTO) {
852		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
853			"GAS: Unexpected IE in GAS Initial Request: %u", *pos);
854		return;
855	}
856	adv_proto = pos++;
857
858	slen = *pos++;
859	next = pos + slen;
860	if (next > end || slen < 2) {
861		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
862			"GAS: Invalid IE in GAS Initial Request");
863		return;
864	}
865	pos++; /* skip QueryRespLenLimit and PAME-BI */
866
867	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
868		struct wpabuf *buf;
869		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
870			"GAS: Unsupported GAS advertisement protocol id %u",
871			*pos);
872		if (sa[0] & 0x01)
873			return; /* Invalid source address - drop silently */
874		buf = gas_build_initial_resp(
875			dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED,
876			0, 2 + slen + 2);
877		if (buf == NULL)
878			return;
879		wpabuf_put_data(buf, adv_proto, 2 + slen);
880		wpabuf_put_le16(buf, 0); /* Query Response Length */
881		hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
882					wpabuf_head(buf), wpabuf_len(buf));
883		wpabuf_free(buf);
884		return;
885	}
886
887	pos = next;
888	/* Query Request */
889	if (pos + 2 > end)
890		return;
891	slen = WPA_GET_LE16(pos);
892	pos += 2;
893	if (pos + slen > end)
894		return;
895	end = pos + slen;
896
897	/* ANQP Query Request */
898	while (pos < end) {
899		u16 info_id, elen;
900
901		if (pos + 4 > end)
902			return;
903
904		info_id = WPA_GET_LE16(pos);
905		pos += 2;
906		elen = WPA_GET_LE16(pos);
907		pos += 2;
908
909		if (pos + elen > end) {
910			wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
911			return;
912		}
913
914		switch (info_id) {
915		case ANQP_QUERY_LIST:
916			rx_anqp_query_list(hapd, pos, pos + elen, &qi);
917			break;
918#ifdef CONFIG_HS20
919		case ANQP_VENDOR_SPECIFIC:
920			rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi);
921			break;
922#endif /* CONFIG_HS20 */
923		default:
924			wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
925				   "Request element %u", info_id);
926			break;
927		}
928
929		pos += elen;
930	}
931
932	gas_serv_req_local_processing(hapd, sa, dialog_token, &qi);
933}
934
935
936void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
937			      struct gas_dialog_info *dialog)
938{
939	struct wpabuf *buf, *tx_buf;
940	u8 dialog_token = dialog->dialog_token;
941	size_t frag_len;
942
943	if (dialog->sd_resp == NULL) {
944		buf = gas_serv_build_gas_resp_payload(hapd,
945						      dialog->all_requested,
946						      dialog, NULL, 0);
947		wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
948			buf);
949		if (!buf)
950			goto tx_gas_response_done;
951		dialog->sd_resp = buf;
952		dialog->sd_resp_pos = 0;
953	}
954	frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
955	if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay ||
956	    hapd->conf->gas_comeback_delay) {
957		u16 comeback_delay_tus = dialog->comeback_delay +
958			GAS_SERV_COMEBACK_DELAY_FUDGE;
959		u32 comeback_delay_secs, comeback_delay_usecs;
960
961		if (hapd->conf->gas_comeback_delay) {
962			/* Testing - allow overriding of the delay value */
963			comeback_delay_tus = hapd->conf->gas_comeback_delay;
964		}
965
966		wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit "
967			   "%u) and comeback delay %u, "
968			   "requesting comebacks", (unsigned int) frag_len,
969			   (unsigned int) hapd->gas_frag_limit,
970			   dialog->comeback_delay);
971		tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
972							 WLAN_STATUS_SUCCESS,
973							 comeback_delay_tus,
974							 NULL);
975		if (tx_buf) {
976			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
977				"GAS: Tx GAS Initial Resp (comeback = 10TU)");
978			hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
979						dst,
980						wpabuf_head(tx_buf),
981						wpabuf_len(tx_buf));
982		}
983		wpabuf_free(tx_buf);
984
985		/* start a timer of 1.5 * comeback-delay */
986		comeback_delay_tus = comeback_delay_tus +
987			(comeback_delay_tus / 2);
988		comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000;
989		comeback_delay_usecs = (comeback_delay_tus * 1024) -
990			(comeback_delay_secs * 1000000);
991		eloop_register_timeout(comeback_delay_secs,
992				       comeback_delay_usecs,
993				       gas_serv_clear_cached_ies, dialog,
994				       NULL);
995		goto tx_gas_response_done;
996	}
997
998	buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
999				dialog->sd_resp_pos, frag_len);
1000	if (buf == NULL) {
1001		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation "
1002			"failed");
1003		goto tx_gas_response_done;
1004	}
1005	tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
1006						 WLAN_STATUS_SUCCESS, 0, buf);
1007	wpabuf_free(buf);
1008	if (tx_buf == NULL)
1009		goto tx_gas_response_done;
1010	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial "
1011		"Response (frag_id %d frag_len %d)",
1012		dialog->sd_frag_id, (int) frag_len);
1013	dialog->sd_frag_id++;
1014
1015	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
1016				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
1017	wpabuf_free(tx_buf);
1018tx_gas_response_done:
1019	gas_serv_clear_cached_ies(dialog, NULL);
1020}
1021
1022
1023static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
1024					 const u8 *sa,
1025					 const u8 *data, size_t len)
1026{
1027	struct gas_dialog_info *dialog;
1028	struct wpabuf *buf, *tx_buf;
1029	u8 dialog_token;
1030	size_t frag_len;
1031	int more = 0;
1032
1033	wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len);
1034	if (len < 1)
1035		return;
1036	dialog_token = *data;
1037	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u",
1038		dialog_token);
1039
1040	dialog = gas_serv_dialog_find(hapd, sa, dialog_token);
1041	if (!dialog) {
1042		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD "
1043			"response fragment for " MACSTR " dialog token %u",
1044			MAC2STR(sa), dialog_token);
1045
1046		if (sa[0] & 0x01)
1047			return; /* Invalid source address - drop silently */
1048		tx_buf = gas_anqp_build_comeback_resp_buf(
1049			dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0,
1050			0, NULL);
1051		if (tx_buf == NULL)
1052			return;
1053		goto send_resp;
1054	}
1055
1056	if (dialog->sd_resp == NULL) {
1057		wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x",
1058			   dialog->requested, dialog->received);
1059		if ((dialog->requested & dialog->received) !=
1060		    dialog->requested) {
1061			wpa_printf(MSG_DEBUG, "GAS: Did not receive response "
1062				   "from remote processing");
1063			gas_serv_dialog_clear(dialog);
1064			tx_buf = gas_anqp_build_comeback_resp_buf(
1065				dialog_token,
1066				WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0,
1067				NULL);
1068			if (tx_buf == NULL)
1069				return;
1070			goto send_resp;
1071		}
1072
1073		buf = gas_serv_build_gas_resp_payload(hapd,
1074						      dialog->all_requested,
1075						      dialog, NULL, 0);
1076		wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
1077			buf);
1078		if (!buf)
1079			goto rx_gas_comeback_req_done;
1080		dialog->sd_resp = buf;
1081		dialog->sd_resp_pos = 0;
1082	}
1083	frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
1084	if (frag_len > hapd->gas_frag_limit) {
1085		frag_len = hapd->gas_frag_limit;
1086		more = 1;
1087	}
1088	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
1089		(unsigned int) frag_len);
1090	buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
1091				dialog->sd_resp_pos, frag_len);
1092	if (buf == NULL) {
1093		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
1094			"buffer");
1095		goto rx_gas_comeback_req_done;
1096	}
1097	tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
1098						  WLAN_STATUS_SUCCESS,
1099						  dialog->sd_frag_id,
1100						  more, 0, buf);
1101	wpabuf_free(buf);
1102	if (tx_buf == NULL)
1103		goto rx_gas_comeback_req_done;
1104	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
1105		"(frag_id %d more=%d frag_len=%d)",
1106		dialog->sd_frag_id, more, (int) frag_len);
1107	dialog->sd_frag_id++;
1108	dialog->sd_resp_pos += frag_len;
1109
1110	if (more) {
1111		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain "
1112			"to be sent",
1113			(int) (wpabuf_len(dialog->sd_resp) -
1114			       dialog->sd_resp_pos));
1115	} else {
1116		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
1117			"SD response sent");
1118		gas_serv_dialog_clear(dialog);
1119		gas_serv_free_dialogs(hapd, sa);
1120	}
1121
1122send_resp:
1123	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
1124				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
1125	wpabuf_free(tx_buf);
1126	return;
1127
1128rx_gas_comeback_req_done:
1129	gas_serv_clear_cached_ies(dialog, NULL);
1130}
1131
1132
1133static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
1134				      int freq)
1135{
1136	struct hostapd_data *hapd = ctx;
1137	const struct ieee80211_mgmt *mgmt;
1138	size_t hdr_len;
1139	const u8 *sa, *data;
1140
1141	mgmt = (const struct ieee80211_mgmt *) buf;
1142	hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
1143	if (hdr_len > len)
1144		return;
1145	if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
1146		return;
1147	sa = mgmt->sa;
1148	len -= hdr_len;
1149	data = &mgmt->u.action.u.public_action.action;
1150	switch (data[0]) {
1151	case WLAN_PA_GAS_INITIAL_REQ:
1152		gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1);
1153		break;
1154	case WLAN_PA_GAS_COMEBACK_REQ:
1155		gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1);
1156		break;
1157	}
1158}
1159
1160
1161int gas_serv_init(struct hostapd_data *hapd)
1162{
1163	hapd->public_action_cb2 = gas_serv_rx_public_action;
1164	hapd->public_action_cb2_ctx = hapd;
1165	hapd->gas_frag_limit = 1400;
1166	if (hapd->conf->gas_frag_limit > 0)
1167		hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
1168	return 0;
1169}
1170
1171
1172void gas_serv_deinit(struct hostapd_data *hapd)
1173{
1174}
1175