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