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