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