2 * Generic advertisement service (GAS) server
3 * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
12 #include "common/ieee802_11_defs.h"
13 #include "common/gas.h"
14 #include "common/wpa_ctrl.h"
15 #include "utils/eloop.h"
17 #include "ap_config.h"
18 #include "ap_drv_ops.h"
19 #include "dpp_hostapd.h"
25 static void gas_serv_write_dpp_adv_proto(struct wpabuf *buf)
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);
36 #endif /* CONFIG_DPP */
39 static void convert_to_protected_dual(struct wpabuf *msg)
41 u8 *categ = wpabuf_mhead_u8(msg);
42 *categ = WLAN_ACTION_PROTECTED_DUAL;
46 static struct gas_dialog_info *
47 gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
50 struct gas_dialog_info *dia = NULL;
53 sta = ap_get_sta(hapd, addr);
56 * We need a STA entry to be able to maintain state for
59 wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for "
61 sta = ap_sta_add(hapd, addr);
63 wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR
64 " for GAS query", MAC2STR(addr));
67 sta->flags |= WLAN_STA_GAS;
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.
73 ap_sta_session_timeout(hapd, sta,
74 hapd->conf->gas_comeback_delay / 1024 +
77 ap_sta_replenish_timeout(hapd, sta, 5);
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)
87 for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) {
88 if (i == GAS_DIALOG_MAX)
90 if (sta->gas_dialog[i].valid)
92 dia = &sta->gas_dialog[i];
94 dia->dialog_token = dialog_token;
95 sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i;
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);
107 struct gas_dialog_info *
108 gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
111 struct sta_info *sta;
114 sta = ap_get_sta(hapd, addr);
116 wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR,
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)
124 ap_sta_replenish_timeout(hapd, sta, 5);
125 return &sta->gas_dialog[i];
127 wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
128 MACSTR " dialog_token %u", MAC2STR(addr), dialog_token);
133 void gas_serv_dialog_clear(struct gas_dialog_info *dia)
135 wpabuf_free(dia->sd_resp);
136 os_memset(dia, 0, sizeof(*dia));
140 static void gas_serv_free_dialogs(struct hostapd_data *hapd,
143 struct sta_info *sta;
146 sta = ap_get_sta(hapd, sta_addr);
147 if (sta == NULL || sta->gas_dialog == NULL)
150 for (i = 0; i < GAS_DIALOG_MAX; i++) {
151 if (sta->gas_dialog[i].valid)
155 os_free(sta->gas_dialog);
156 sta->gas_dialog = NULL;
161 static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
166 len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
167 wpabuf_put_be24(buf, OUI_WFA);
168 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
169 wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
170 wpabuf_put_u8(buf, 0); /* Reserved */
171 wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
172 if (hapd->conf->hs20_oper_friendly_name)
173 wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
174 if (hapd->conf->hs20_wan_metrics)
175 wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
176 if (hapd->conf->hs20_connection_capability)
177 wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
178 if (hapd->conf->nai_realm_data)
179 wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
180 if (hapd->conf->hs20_operating_class)
181 wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
182 if (hapd->conf->hs20_osu_providers_count)
183 wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
184 if (hapd->conf->hs20_osu_providers_nai_count)
185 wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
186 if (hapd->conf->hs20_icons_count)
187 wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
188 if (hapd->conf->hs20_operator_icon_count)
189 wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
190 gas_anqp_set_element_len(buf, len);
192 #endif /* CONFIG_HS20 */
195 static struct anqp_element * get_anqp_elem(struct hostapd_data *hapd,
198 struct anqp_element *elem;
200 dl_list_for_each(elem, &hapd->conf->anqp_elem, struct anqp_element,
202 if (elem->infoid == infoid)
210 static void anqp_add_elem(struct hostapd_data *hapd, struct wpabuf *buf,
213 struct anqp_element *elem;
215 elem = get_anqp_elem(hapd, infoid);
218 if (wpabuf_tailroom(buf) < 2 + 2 + wpabuf_len(elem->payload)) {
219 wpa_printf(MSG_DEBUG, "ANQP: No room for InfoID %u payload",
224 wpabuf_put_le16(buf, infoid);
225 wpabuf_put_le16(buf, wpabuf_len(elem->payload));
226 wpabuf_put_buf(buf, elem->payload);
230 static int anqp_add_override(struct hostapd_data *hapd, struct wpabuf *buf,
233 if (get_anqp_elem(hapd, infoid)) {
234 anqp_add_elem(hapd, buf, infoid);
242 static void anqp_add_capab_list(struct hostapd_data *hapd,
248 if (anqp_add_override(hapd, buf, ANQP_CAPABILITY_LIST))
251 len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
252 wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
253 if (hapd->conf->venue_name || get_anqp_elem(hapd, ANQP_VENUE_NAME))
254 wpabuf_put_le16(buf, ANQP_VENUE_NAME);
255 if (get_anqp_elem(hapd, ANQP_EMERGENCY_CALL_NUMBER))
256 wpabuf_put_le16(buf, ANQP_EMERGENCY_CALL_NUMBER);
257 if (hapd->conf->network_auth_type ||
258 get_anqp_elem(hapd, ANQP_NETWORK_AUTH_TYPE))
259 wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
260 if (hapd->conf->roaming_consortium ||
261 get_anqp_elem(hapd, ANQP_ROAMING_CONSORTIUM))
262 wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
263 if (hapd->conf->ipaddr_type_configured ||
264 get_anqp_elem(hapd, ANQP_IP_ADDR_TYPE_AVAILABILITY))
265 wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
266 if (hapd->conf->nai_realm_data ||
267 get_anqp_elem(hapd, ANQP_NAI_REALM))
268 wpabuf_put_le16(buf, ANQP_NAI_REALM);
269 if (hapd->conf->anqp_3gpp_cell_net ||
270 get_anqp_elem(hapd, ANQP_3GPP_CELLULAR_NETWORK))
271 wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
272 if (get_anqp_elem(hapd, ANQP_AP_GEOSPATIAL_LOCATION))
273 wpabuf_put_le16(buf, ANQP_AP_GEOSPATIAL_LOCATION);
274 if (get_anqp_elem(hapd, ANQP_AP_CIVIC_LOCATION))
275 wpabuf_put_le16(buf, ANQP_AP_CIVIC_LOCATION);
276 if (get_anqp_elem(hapd, ANQP_AP_LOCATION_PUBLIC_URI))
277 wpabuf_put_le16(buf, ANQP_AP_LOCATION_PUBLIC_URI);
278 if (hapd->conf->domain_name || get_anqp_elem(hapd, ANQP_DOMAIN_NAME))
279 wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
280 if (get_anqp_elem(hapd, ANQP_EMERGENCY_ALERT_URI))
281 wpabuf_put_le16(buf, ANQP_EMERGENCY_ALERT_URI);
282 if (get_anqp_elem(hapd, ANQP_TDLS_CAPABILITY))
283 wpabuf_put_le16(buf, ANQP_TDLS_CAPABILITY);
284 if (get_anqp_elem(hapd, ANQP_EMERGENCY_NAI))
285 wpabuf_put_le16(buf, ANQP_EMERGENCY_NAI);
286 if (get_anqp_elem(hapd, ANQP_NEIGHBOR_REPORT))
287 wpabuf_put_le16(buf, ANQP_NEIGHBOR_REPORT);
289 if (!dl_list_empty(&hapd->conf->fils_realms) ||
290 get_anqp_elem(hapd, ANQP_FILS_REALM_INFO))
291 wpabuf_put_le16(buf, ANQP_FILS_REALM_INFO);
292 #endif /* CONFIG_FILS */
293 if (get_anqp_elem(hapd, ANQP_CAG))
294 wpabuf_put_le16(buf, ANQP_CAG);
295 if (hapd->conf->venue_url || get_anqp_elem(hapd, ANQP_VENUE_URL))
296 wpabuf_put_le16(buf, ANQP_VENUE_URL);
297 if (get_anqp_elem(hapd, ANQP_ADVICE_OF_CHARGE))
298 wpabuf_put_le16(buf, ANQP_ADVICE_OF_CHARGE);
299 if (get_anqp_elem(hapd, ANQP_LOCAL_CONTENT))
300 wpabuf_put_le16(buf, ANQP_LOCAL_CONTENT);
301 for (id = 280; id < 300; id++) {
302 if (get_anqp_elem(hapd, id))
303 wpabuf_put_le16(buf, id);
306 anqp_add_hs_capab_list(hapd, buf);
307 #endif /* CONFIG_HS20 */
308 gas_anqp_set_element_len(buf, len);
312 static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
314 if (anqp_add_override(hapd, buf, ANQP_VENUE_NAME))
317 if (hapd->conf->venue_name) {
320 len = gas_anqp_add_element(buf, ANQP_VENUE_NAME);
321 wpabuf_put_u8(buf, hapd->conf->venue_group);
322 wpabuf_put_u8(buf, hapd->conf->venue_type);
323 for (i = 0; i < hapd->conf->venue_name_count; i++) {
324 struct hostapd_lang_string *vn;
325 vn = &hapd->conf->venue_name[i];
326 wpabuf_put_u8(buf, 3 + vn->name_len);
327 wpabuf_put_data(buf, vn->lang, 3);
328 wpabuf_put_data(buf, vn->name, vn->name_len);
330 gas_anqp_set_element_len(buf, len);
335 static void anqp_add_venue_url(struct hostapd_data *hapd, struct wpabuf *buf)
337 if (anqp_add_override(hapd, buf, ANQP_VENUE_URL))
340 if (hapd->conf->venue_url) {
344 len = gas_anqp_add_element(buf, ANQP_VENUE_URL);
345 for (i = 0; i < hapd->conf->venue_url_count; i++) {
346 struct hostapd_venue_url *url;
348 url = &hapd->conf->venue_url[i];
349 wpabuf_put_u8(buf, 1 + url->url_len);
350 wpabuf_put_u8(buf, url->venue_number);
351 wpabuf_put_data(buf, url->url, url->url_len);
353 gas_anqp_set_element_len(buf, len);
358 static void anqp_add_network_auth_type(struct hostapd_data *hapd,
361 if (anqp_add_override(hapd, buf, ANQP_NETWORK_AUTH_TYPE))
364 if (hapd->conf->network_auth_type) {
365 wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
366 wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
367 wpabuf_put_data(buf, hapd->conf->network_auth_type,
368 hapd->conf->network_auth_type_len);
373 static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
379 if (anqp_add_override(hapd, buf, ANQP_ROAMING_CONSORTIUM))
382 len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
383 for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
384 struct hostapd_roaming_consortium *rc;
385 rc = &hapd->conf->roaming_consortium[i];
386 wpabuf_put_u8(buf, rc->len);
387 wpabuf_put_data(buf, rc->oi, rc->len);
389 gas_anqp_set_element_len(buf, len);
393 static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
396 if (anqp_add_override(hapd, buf, ANQP_IP_ADDR_TYPE_AVAILABILITY))
399 if (hapd->conf->ipaddr_type_configured) {
400 wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
401 wpabuf_put_le16(buf, 1);
402 wpabuf_put_u8(buf, hapd->conf->ipaddr_type_availability);
407 static void anqp_add_nai_realm_eap(struct wpabuf *buf,
408 struct hostapd_nai_realm_data *realm)
412 wpabuf_put_u8(buf, realm->eap_method_count);
414 for (i = 0; i < realm->eap_method_count; i++) {
415 struct hostapd_nai_realm_eap *eap = &realm->eap_method[i];
416 wpabuf_put_u8(buf, 2 + (3 * eap->num_auths));
417 wpabuf_put_u8(buf, eap->eap_method);
418 wpabuf_put_u8(buf, eap->num_auths);
419 for (j = 0; j < eap->num_auths; j++) {
420 wpabuf_put_u8(buf, eap->auth_id[j]);
421 wpabuf_put_u8(buf, 1);
422 wpabuf_put_u8(buf, eap->auth_val[j]);
428 static void anqp_add_nai_realm_data(struct wpabuf *buf,
429 struct hostapd_nai_realm_data *realm,
430 unsigned int realm_idx)
434 wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx],
435 (int) os_strlen(realm->realm[realm_idx]));
436 realm_data_len = wpabuf_put(buf, 2);
437 wpabuf_put_u8(buf, realm->encoding);
438 wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx]));
439 wpabuf_put_str(buf, realm->realm[realm_idx]);
440 anqp_add_nai_realm_eap(buf, realm);
441 gas_anqp_set_element_len(buf, realm_data_len);
445 static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
447 const u8 *home_realm,
448 size_t home_realm_len)
450 unsigned int i, j, k;
451 u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len;
452 struct hostapd_nai_realm_data *realm;
453 const u8 *pos, *realm_name, *end;
455 unsigned int realm_data_idx;
456 unsigned int realm_idx;
460 end = pos + home_realm_len;
462 wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
463 home_realm, home_realm_len);
468 for (i = 0; i < num_realms && num_matching < 10; i++) {
470 wpa_hexdump(MSG_DEBUG,
471 "Truncated NAI Home Realm Query",
472 home_realm, home_realm_len);
477 if (realm_len > end - pos) {
478 wpa_hexdump(MSG_DEBUG,
479 "Truncated NAI Home Realm Query",
480 home_realm, home_realm_len);
484 for (j = 0; j < hapd->conf->nai_realm_count &&
485 num_matching < 10; j++) {
486 const u8 *rpos, *rend;
487 realm = &hapd->conf->nai_realm_data[j];
488 if (encoding != realm->encoding)
492 while (rpos < realm_name + realm_len &&
495 rend < realm_name + realm_len; rend++) {
499 for (k = 0; k < MAX_NAI_REALMS &&
501 num_matching < 10; k++) {
502 if ((int) os_strlen(realm->realm[k]) !=
504 os_strncmp((char *) rpos,
508 matches[num_matching].realm_data_idx =
510 matches[num_matching].realm_idx = k;
519 realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
520 wpabuf_put_le16(buf, num_matching);
523 * There are two ways to format. 1. each realm in a NAI Realm Data unit
524 * 2. all realms that share the same EAP methods in a NAI Realm Data
525 * unit. The first format is likely to be bigger in size than the
526 * second, but may be easier to parse and process by the receiver.
528 for (i = 0; i < num_matching; i++) {
529 wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d",
530 matches[i].realm_data_idx, matches[i].realm_idx);
531 realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx];
532 anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx);
534 gas_anqp_set_element_len(buf, realm_list_len);
539 static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
540 const u8 *home_realm, size_t home_realm_len,
541 int nai_realm, int nai_home_realm)
543 if (nai_realm && !nai_home_realm &&
544 anqp_add_override(hapd, buf, ANQP_NAI_REALM))
547 if (nai_realm && hapd->conf->nai_realm_data) {
550 len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
551 wpabuf_put_le16(buf, hapd->conf->nai_realm_count);
552 for (i = 0; i < hapd->conf->nai_realm_count; i++) {
553 u8 *realm_data_len, *realm_len;
554 struct hostapd_nai_realm_data *realm;
556 realm = &hapd->conf->nai_realm_data[i];
557 realm_data_len = wpabuf_put(buf, 2);
558 wpabuf_put_u8(buf, realm->encoding);
559 realm_len = wpabuf_put(buf, 1);
560 for (j = 0; realm->realm[j]; j++) {
562 wpabuf_put_u8(buf, ';');
563 wpabuf_put_str(buf, realm->realm[j]);
565 *realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1;
566 anqp_add_nai_realm_eap(buf, realm);
567 gas_anqp_set_element_len(buf, realm_data_len);
569 gas_anqp_set_element_len(buf, len);
570 } else if (nai_home_realm && hapd->conf->nai_realm_data && home_realm) {
571 hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
577 static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
580 if (anqp_add_override(hapd, buf, ANQP_3GPP_CELLULAR_NETWORK))
583 if (hapd->conf->anqp_3gpp_cell_net) {
584 wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
586 hapd->conf->anqp_3gpp_cell_net_len);
587 wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net,
588 hapd->conf->anqp_3gpp_cell_net_len);
593 static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
595 if (anqp_add_override(hapd, buf, ANQP_DOMAIN_NAME))
598 if (hapd->conf->domain_name) {
599 wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
600 wpabuf_put_le16(buf, hapd->conf->domain_name_len);
601 wpabuf_put_data(buf, hapd->conf->domain_name,
602 hapd->conf->domain_name_len);
608 static void anqp_add_fils_realm_info(struct hostapd_data *hapd,
613 if (anqp_add_override(hapd, buf, ANQP_FILS_REALM_INFO))
616 count = dl_list_len(&hapd->conf->fils_realms);
620 struct fils_realm *realm;
622 wpabuf_put_le16(buf, ANQP_FILS_REALM_INFO);
623 wpabuf_put_le16(buf, 2 * count);
625 dl_list_for_each(realm, &hapd->conf->fils_realms,
626 struct fils_realm, list) {
629 wpabuf_put_data(buf, realm->hash, 2);
634 #endif /* CONFIG_FILS */
639 static void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
642 if (hapd->conf->hs20_oper_friendly_name) {
645 len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
646 wpabuf_put_be24(buf, OUI_WFA);
647 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
648 wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
649 wpabuf_put_u8(buf, 0); /* Reserved */
650 for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++)
652 struct hostapd_lang_string *vn;
653 vn = &hapd->conf->hs20_oper_friendly_name[i];
654 wpabuf_put_u8(buf, 3 + vn->name_len);
655 wpabuf_put_data(buf, vn->lang, 3);
656 wpabuf_put_data(buf, vn->name, vn->name_len);
658 gas_anqp_set_element_len(buf, len);
663 static void anqp_add_wan_metrics(struct hostapd_data *hapd,
666 if (hapd->conf->hs20_wan_metrics) {
667 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
668 wpabuf_put_be24(buf, OUI_WFA);
669 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
670 wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
671 wpabuf_put_u8(buf, 0); /* Reserved */
672 wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13);
673 gas_anqp_set_element_len(buf, len);
678 static void anqp_add_connection_capability(struct hostapd_data *hapd,
681 if (hapd->conf->hs20_connection_capability) {
682 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
683 wpabuf_put_be24(buf, OUI_WFA);
684 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
685 wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
686 wpabuf_put_u8(buf, 0); /* Reserved */
687 wpabuf_put_data(buf, hapd->conf->hs20_connection_capability,
688 hapd->conf->hs20_connection_capability_len);
689 gas_anqp_set_element_len(buf, len);
694 static void anqp_add_operating_class(struct hostapd_data *hapd,
697 if (hapd->conf->hs20_operating_class) {
698 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
699 wpabuf_put_be24(buf, OUI_WFA);
700 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
701 wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
702 wpabuf_put_u8(buf, 0); /* Reserved */
703 wpabuf_put_data(buf, hapd->conf->hs20_operating_class,
704 hapd->conf->hs20_operating_class_len);
705 gas_anqp_set_element_len(buf, len);
710 static void anqp_add_icon(struct wpabuf *buf, struct hostapd_bss_config *bss,
714 struct hs20_icon *icon = NULL;
716 for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
717 if (os_strcmp(name, bss->hs20_icons[j].name) == 0)
718 icon = &bss->hs20_icons[j];
721 return; /* icon info not found */
723 wpabuf_put_le16(buf, icon->width);
724 wpabuf_put_le16(buf, icon->height);
725 wpabuf_put_data(buf, icon->language, 3);
726 wpabuf_put_u8(buf, os_strlen(icon->type));
727 wpabuf_put_str(buf, icon->type);
728 wpabuf_put_u8(buf, os_strlen(icon->name));
729 wpabuf_put_str(buf, icon->name);
733 static void anqp_add_osu_provider(struct wpabuf *buf,
734 struct hostapd_bss_config *bss,
735 struct hs20_osu_provider *p)
737 u8 *len, *len2, *count;
740 len = wpabuf_put(buf, 2); /* OSU Provider Length to be filled */
742 /* OSU Friendly Name Duples */
743 len2 = wpabuf_put(buf, 2);
744 for (i = 0; i < p->friendly_name_count; i++) {
745 struct hostapd_lang_string *s = &p->friendly_name[i];
746 wpabuf_put_u8(buf, 3 + s->name_len);
747 wpabuf_put_data(buf, s->lang, 3);
748 wpabuf_put_data(buf, s->name, s->name_len);
750 WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
754 wpabuf_put_u8(buf, os_strlen(p->server_uri));
755 wpabuf_put_str(buf, p->server_uri);
757 wpabuf_put_u8(buf, 0);
759 /* OSU Method List */
760 count = wpabuf_put(buf, 1);
761 for (i = 0; p->method_list && p->method_list[i] >= 0; i++)
762 wpabuf_put_u8(buf, p->method_list[i]);
765 /* Icons Available */
766 len2 = wpabuf_put(buf, 2);
767 for (i = 0; i < p->icons_count; i++)
768 anqp_add_icon(buf, bss, p->icons[i]);
769 WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
773 wpabuf_put_u8(buf, os_strlen(p->osu_nai));
774 wpabuf_put_str(buf, p->osu_nai);
776 wpabuf_put_u8(buf, 0);
778 /* OSU Service Description Duples */
779 len2 = wpabuf_put(buf, 2);
780 for (i = 0; i < p->service_desc_count; i++) {
781 struct hostapd_lang_string *s = &p->service_desc[i];
782 wpabuf_put_u8(buf, 3 + s->name_len);
783 wpabuf_put_data(buf, s->lang, 3);
784 wpabuf_put_data(buf, s->name, s->name_len);
786 WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
788 WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
792 static void anqp_add_osu_providers_list(struct hostapd_data *hapd,
795 if (hapd->conf->hs20_osu_providers_count) {
797 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
798 wpabuf_put_be24(buf, OUI_WFA);
799 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
800 wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
801 wpabuf_put_u8(buf, 0); /* Reserved */
804 wpabuf_put_u8(buf, hapd->conf->osu_ssid_len);
805 wpabuf_put_data(buf, hapd->conf->osu_ssid,
806 hapd->conf->osu_ssid_len);
808 /* Number of OSU Providers */
809 wpabuf_put_u8(buf, hapd->conf->hs20_osu_providers_count);
811 for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
812 anqp_add_osu_provider(
814 &hapd->conf->hs20_osu_providers[i]);
817 gas_anqp_set_element_len(buf, len);
822 static void anqp_add_osu_provider_nai(struct wpabuf *buf,
823 struct hs20_osu_provider *p)
825 /* OSU_NAI for shared BSS (Single SSID) */
827 wpabuf_put_u8(buf, os_strlen(p->osu_nai2));
828 wpabuf_put_str(buf, p->osu_nai2);
830 wpabuf_put_u8(buf, 0);
835 static void anqp_add_osu_providers_nai_list(struct hostapd_data *hapd,
838 if (hapd->conf->hs20_osu_providers_nai_count) {
840 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
841 wpabuf_put_be24(buf, OUI_WFA);
842 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
843 wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
844 wpabuf_put_u8(buf, 0); /* Reserved */
846 for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
847 anqp_add_osu_provider_nai(
848 buf, &hapd->conf->hs20_osu_providers[i]);
851 gas_anqp_set_element_len(buf, len);
856 static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
858 const u8 *name, size_t name_len)
860 struct hs20_icon *icon;
864 wpa_hexdump_ascii(MSG_DEBUG, "HS 2.0: Requested Icon Filename",
866 for (i = 0; i < hapd->conf->hs20_icons_count; i++) {
867 icon = &hapd->conf->hs20_icons[i];
868 if (name_len == os_strlen(icon->name) &&
869 os_memcmp(name, icon->name, name_len) == 0)
873 if (i < hapd->conf->hs20_icons_count)
874 icon = &hapd->conf->hs20_icons[i];
878 len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
879 wpabuf_put_be24(buf, OUI_WFA);
880 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
881 wpabuf_put_u8(buf, HS20_STYPE_ICON_BINARY_FILE);
882 wpabuf_put_u8(buf, 0); /* Reserved */
888 data = os_readfile(icon->file, &data_len);
889 if (data == NULL || data_len > 65535) {
890 wpabuf_put_u8(buf, 2); /* Download Status:
891 * Unspecified file error */
892 wpabuf_put_u8(buf, 0);
893 wpabuf_put_le16(buf, 0);
895 wpabuf_put_u8(buf, 0); /* Download Status: Success */
896 wpabuf_put_u8(buf, os_strlen(icon->type));
897 wpabuf_put_str(buf, icon->type);
898 wpabuf_put_le16(buf, data_len);
899 wpabuf_put_data(buf, data, data_len);
903 wpabuf_put_u8(buf, 1); /* Download Status: File not found */
904 wpabuf_put_u8(buf, 0);
905 wpabuf_put_le16(buf, 0);
908 gas_anqp_set_element_len(buf, len);
912 static void anqp_add_operator_icon_metadata(struct hostapd_data *hapd,
915 struct hostapd_bss_config *bss = hapd->conf;
919 if (!bss->hs20_operator_icon_count)
922 len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
924 wpabuf_put_be24(buf, OUI_WFA);
925 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
926 wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
927 wpabuf_put_u8(buf, 0); /* Reserved */
929 for (i = 0; i < bss->hs20_operator_icon_count; i++)
930 anqp_add_icon(buf, bss, bss->hs20_operator_icon[i]);
932 gas_anqp_set_element_len(buf, len);
935 #endif /* CONFIG_HS20 */
939 static void anqp_add_mbo_cell_data_conn_pref(struct hostapd_data *hapd,
942 if (hapd->conf->mbo_cell_data_conn_pref >= 0) {
943 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
944 wpabuf_put_be24(buf, OUI_WFA);
945 wpabuf_put_u8(buf, MBO_ANQP_OUI_TYPE);
946 wpabuf_put_u8(buf, MBO_ANQP_SUBTYPE_CELL_CONN_PREF);
947 wpabuf_put_u8(buf, hapd->conf->mbo_cell_data_conn_pref);
948 gas_anqp_set_element_len(buf, len);
951 #endif /* CONFIG_MBO */
954 static size_t anqp_get_required_len(struct hostapd_data *hapd,
956 unsigned int num_infoid)
961 for (i = 0; i < num_infoid; i++) {
962 struct anqp_element *elem = get_anqp_elem(hapd, infoid[i]);
965 len += 2 + 2 + wpabuf_len(elem->payload);
972 static struct wpabuf *
973 gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
974 unsigned int request,
975 const u8 *home_realm, size_t home_realm_len,
976 const u8 *icon_name, size_t icon_name_len,
977 const u16 *extra_req,
978 unsigned int num_extra_req)
985 if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
987 if (request & ANQP_REQ_ICON_REQUEST)
990 if (request & ANQP_FILS_REALM_INFO)
991 len += 2 * dl_list_len(&hapd->conf->fils_realms);
992 #endif /* CONFIG_FILS */
993 len += anqp_get_required_len(hapd, extra_req, num_extra_req);
995 buf = wpabuf_alloc(len);
999 if (request & ANQP_REQ_CAPABILITY_LIST)
1000 anqp_add_capab_list(hapd, buf);
1001 if (request & ANQP_REQ_VENUE_NAME)
1002 anqp_add_venue_name(hapd, buf);
1003 if (request & ANQP_REQ_EMERGENCY_CALL_NUMBER)
1004 anqp_add_elem(hapd, buf, ANQP_EMERGENCY_CALL_NUMBER);
1005 if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
1006 anqp_add_network_auth_type(hapd, buf);
1007 if (request & ANQP_REQ_ROAMING_CONSORTIUM)
1008 anqp_add_roaming_consortium(hapd, buf);
1009 if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY)
1010 anqp_add_ip_addr_type_availability(hapd, buf);
1011 if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
1012 anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len,
1013 request & ANQP_REQ_NAI_REALM,
1014 request & ANQP_REQ_NAI_HOME_REALM);
1015 if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
1016 anqp_add_3gpp_cellular_network(hapd, buf);
1017 if (request & ANQP_REQ_AP_GEOSPATIAL_LOCATION)
1018 anqp_add_elem(hapd, buf, ANQP_AP_GEOSPATIAL_LOCATION);
1019 if (request & ANQP_REQ_AP_CIVIC_LOCATION)
1020 anqp_add_elem(hapd, buf, ANQP_AP_CIVIC_LOCATION);
1021 if (request & ANQP_REQ_AP_LOCATION_PUBLIC_URI)
1022 anqp_add_elem(hapd, buf, ANQP_AP_LOCATION_PUBLIC_URI);
1023 if (request & ANQP_REQ_DOMAIN_NAME)
1024 anqp_add_domain_name(hapd, buf);
1025 if (request & ANQP_REQ_EMERGENCY_ALERT_URI)
1026 anqp_add_elem(hapd, buf, ANQP_EMERGENCY_ALERT_URI);
1027 if (request & ANQP_REQ_TDLS_CAPABILITY)
1028 anqp_add_elem(hapd, buf, ANQP_TDLS_CAPABILITY);
1029 if (request & ANQP_REQ_EMERGENCY_NAI)
1030 anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
1032 for (i = 0; i < num_extra_req; i++) {
1034 if (extra_req[i] == ANQP_FILS_REALM_INFO) {
1035 anqp_add_fils_realm_info(hapd, buf);
1038 #endif /* CONFIG_FILS */
1039 if (extra_req[i] == ANQP_VENUE_URL) {
1040 anqp_add_venue_url(hapd, buf);
1043 anqp_add_elem(hapd, buf, extra_req[i]);
1047 if (request & ANQP_REQ_HS_CAPABILITY_LIST)
1048 anqp_add_hs_capab_list(hapd, buf);
1049 if (request & ANQP_REQ_OPERATOR_FRIENDLY_NAME)
1050 anqp_add_operator_friendly_name(hapd, buf);
1051 if (request & ANQP_REQ_WAN_METRICS)
1052 anqp_add_wan_metrics(hapd, buf);
1053 if (request & ANQP_REQ_CONNECTION_CAPABILITY)
1054 anqp_add_connection_capability(hapd, buf);
1055 if (request & ANQP_REQ_OPERATING_CLASS)
1056 anqp_add_operating_class(hapd, buf);
1057 if (request & ANQP_REQ_OSU_PROVIDERS_LIST)
1058 anqp_add_osu_providers_list(hapd, buf);
1059 if (request & ANQP_REQ_ICON_REQUEST)
1060 anqp_add_icon_binary_file(hapd, buf, icon_name, icon_name_len);
1061 if (request & ANQP_REQ_OPERATOR_ICON_METADATA)
1062 anqp_add_operator_icon_metadata(hapd, buf);
1063 if (request & ANQP_REQ_OSU_PROVIDERS_NAI_LIST)
1064 anqp_add_osu_providers_nai_list(hapd, buf);
1065 #endif /* CONFIG_HS20 */
1068 if (request & ANQP_REQ_MBO_CELL_DATA_CONN_PREF)
1069 anqp_add_mbo_cell_data_conn_pref(hapd, buf);
1070 #endif /* CONFIG_MBO */
1076 #define ANQP_MAX_EXTRA_REQ 20
1078 struct anqp_query_info {
1079 unsigned int request;
1080 const u8 *home_realm_query;
1081 size_t home_realm_query_len;
1082 const u8 *icon_name;
1083 size_t icon_name_len;
1085 u16 extra_req[ANQP_MAX_EXTRA_REQ];
1086 unsigned int num_extra_req;
1090 static void set_anqp_req(unsigned int bit, const char *name, int local,
1091 struct anqp_query_info *qi)
1095 wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name);
1097 wpa_printf(MSG_DEBUG, "ANQP: %s not available", name);
1102 static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
1103 struct anqp_query_info *qi)
1106 case ANQP_CAPABILITY_LIST:
1107 set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1,
1110 case ANQP_VENUE_NAME:
1111 set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
1112 hapd->conf->venue_name != NULL, qi);
1114 case ANQP_EMERGENCY_CALL_NUMBER:
1115 set_anqp_req(ANQP_REQ_EMERGENCY_CALL_NUMBER,
1116 "Emergency Call Number",
1117 get_anqp_elem(hapd, info_id) != NULL, qi);
1119 case ANQP_NETWORK_AUTH_TYPE:
1120 set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
1121 hapd->conf->network_auth_type != NULL, qi);
1123 case ANQP_ROAMING_CONSORTIUM:
1124 set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
1125 hapd->conf->roaming_consortium != NULL, qi);
1127 case ANQP_IP_ADDR_TYPE_AVAILABILITY:
1128 set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY,
1129 "IP Addr Type Availability",
1130 hapd->conf->ipaddr_type_configured, qi);
1132 case ANQP_NAI_REALM:
1133 set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm",
1134 hapd->conf->nai_realm_data != NULL, qi);
1136 case ANQP_3GPP_CELLULAR_NETWORK:
1137 set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
1138 "3GPP Cellular Network",
1139 hapd->conf->anqp_3gpp_cell_net != NULL, qi);
1141 case ANQP_AP_GEOSPATIAL_LOCATION:
1142 set_anqp_req(ANQP_REQ_AP_GEOSPATIAL_LOCATION,
1143 "AP Geospatial Location",
1144 get_anqp_elem(hapd, info_id) != NULL, qi);
1146 case ANQP_AP_CIVIC_LOCATION:
1147 set_anqp_req(ANQP_REQ_AP_CIVIC_LOCATION,
1148 "AP Civic Location",
1149 get_anqp_elem(hapd, info_id) != NULL, qi);
1151 case ANQP_AP_LOCATION_PUBLIC_URI:
1152 set_anqp_req(ANQP_REQ_AP_LOCATION_PUBLIC_URI,
1153 "AP Location Public URI",
1154 get_anqp_elem(hapd, info_id) != NULL, qi);
1156 case ANQP_DOMAIN_NAME:
1157 set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
1158 hapd->conf->domain_name != NULL, qi);
1160 case ANQP_EMERGENCY_ALERT_URI:
1161 set_anqp_req(ANQP_REQ_EMERGENCY_ALERT_URI,
1162 "Emergency Alert URI",
1163 get_anqp_elem(hapd, info_id) != NULL, qi);
1165 case ANQP_TDLS_CAPABILITY:
1166 set_anqp_req(ANQP_REQ_TDLS_CAPABILITY,
1168 get_anqp_elem(hapd, info_id) != NULL, qi);
1170 case ANQP_EMERGENCY_NAI:
1171 set_anqp_req(ANQP_REQ_EMERGENCY_NAI,
1173 get_anqp_elem(hapd, info_id) != NULL, qi);
1177 if (info_id == ANQP_FILS_REALM_INFO &&
1178 !dl_list_empty(&hapd->conf->fils_realms)) {
1179 wpa_printf(MSG_DEBUG,
1180 "ANQP: FILS Realm Information (local)");
1182 #endif /* CONFIG_FILS */
1183 if (info_id == ANQP_VENUE_URL && hapd->conf->venue_url) {
1184 wpa_printf(MSG_DEBUG,
1185 "ANQP: Venue URL (local)");
1186 } else if (!get_anqp_elem(hapd, info_id)) {
1187 wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
1191 if (qi->num_extra_req == ANQP_MAX_EXTRA_REQ) {
1192 wpa_printf(MSG_DEBUG,
1193 "ANQP: No more room for extra requests - ignore Info Id %u",
1197 wpa_printf(MSG_DEBUG, "ANQP: Info Id %u (local)", info_id);
1198 qi->extra_req[qi->num_extra_req] = info_id;
1199 qi->num_extra_req++;
1205 static void rx_anqp_query_list(struct hostapd_data *hapd,
1206 const u8 *pos, const u8 *end,
1207 struct anqp_query_info *qi)
1209 wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
1210 (unsigned int) (end - pos) / 2);
1212 while (end - pos >= 2) {
1213 rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
1221 static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
1222 struct anqp_query_info *qi)
1225 case HS20_STYPE_CAPABILITY_LIST:
1226 set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List",
1229 case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
1230 set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME,
1231 "Operator Friendly Name",
1232 hapd->conf->hs20_oper_friendly_name != NULL, qi);
1234 case HS20_STYPE_WAN_METRICS:
1235 set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics",
1236 hapd->conf->hs20_wan_metrics != NULL, qi);
1238 case HS20_STYPE_CONNECTION_CAPABILITY:
1239 set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY,
1240 "Connection Capability",
1241 hapd->conf->hs20_connection_capability != NULL,
1244 case HS20_STYPE_OPERATING_CLASS:
1245 set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class",
1246 hapd->conf->hs20_operating_class != NULL, qi);
1248 case HS20_STYPE_OSU_PROVIDERS_LIST:
1249 set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list",
1250 hapd->conf->hs20_osu_providers_count, qi);
1252 case HS20_STYPE_OPERATOR_ICON_METADATA:
1253 set_anqp_req(ANQP_REQ_OPERATOR_ICON_METADATA,
1254 "Operator Icon Metadata",
1255 hapd->conf->hs20_operator_icon_count, qi);
1257 case HS20_STYPE_OSU_PROVIDERS_NAI_LIST:
1258 set_anqp_req(ANQP_REQ_OSU_PROVIDERS_NAI_LIST,
1259 "OSU Providers NAI List",
1260 hapd->conf->hs20_osu_providers_nai_count, qi);
1263 wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
1270 static void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd,
1271 const u8 *pos, const u8 *end,
1272 struct anqp_query_info *qi)
1274 qi->request |= ANQP_REQ_NAI_HOME_REALM;
1275 qi->home_realm_query = pos;
1276 qi->home_realm_query_len = end - pos;
1277 if (hapd->conf->nai_realm_data != NULL) {
1278 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query "
1281 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not "
1287 static void rx_anqp_hs_icon_request(struct hostapd_data *hapd,
1288 const u8 *pos, const u8 *end,
1289 struct anqp_query_info *qi)
1291 qi->request |= ANQP_REQ_ICON_REQUEST;
1292 qi->icon_name = pos;
1293 qi->icon_name_len = end - pos;
1294 if (hapd->conf->hs20_icons_count) {
1295 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query "
1298 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query not "
1304 static void rx_anqp_vendor_specific_hs20(struct hostapd_data *hapd,
1305 const u8 *pos, const u8 *end,
1306 struct anqp_query_info *qi)
1314 pos++; /* Reserved */
1316 case HS20_STYPE_QUERY_LIST:
1317 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List");
1319 rx_anqp_hs_query_list(hapd, *pos, qi);
1323 case HS20_STYPE_NAI_HOME_REALM_QUERY:
1324 rx_anqp_hs_nai_home_realm(hapd, pos, end, qi);
1326 case HS20_STYPE_ICON_REQUEST:
1327 rx_anqp_hs_icon_request(hapd, pos, end, qi);
1330 wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype "
1336 #endif /* CONFIG_HS20 */
1340 static void rx_anqp_vendor_specific_p2p(struct hostapd_data *hapd,
1341 struct anqp_query_info *qi)
1344 * This is for P2P SD and will be taken care of by the P2P
1345 * implementation. This query needs to be ignored in the generic
1346 * GAS server to avoid duplicated response.
1348 wpa_printf(MSG_DEBUG,
1349 "ANQP: Ignore WFA vendor type %u (P2P SD) in generic GAS server",
1354 #endif /* CONFIG_P2P */
1359 static void rx_anqp_mbo_query_list(struct hostapd_data *hapd, u8 subtype,
1360 struct anqp_query_info *qi)
1363 case MBO_ANQP_SUBTYPE_CELL_CONN_PREF:
1364 set_anqp_req(ANQP_REQ_MBO_CELL_DATA_CONN_PREF,
1365 "Cellular Data Connection Preference",
1366 hapd->conf->mbo_cell_data_conn_pref >= 0, qi);
1369 wpa_printf(MSG_DEBUG, "ANQP: Unsupported MBO subtype %u",
1376 static void rx_anqp_vendor_specific_mbo(struct hostapd_data *hapd,
1377 const u8 *pos, const u8 *end,
1378 struct anqp_query_info *qi)
1387 case MBO_ANQP_SUBTYPE_QUERY_LIST:
1388 wpa_printf(MSG_DEBUG, "ANQP: MBO Query List");
1390 rx_anqp_mbo_query_list(hapd, *pos, qi);
1395 wpa_printf(MSG_DEBUG, "ANQP: Unsupported MBO query subtype %u",
1401 #endif /* CONFIG_MBO */
1404 static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
1405 const u8 *pos, const u8 *end,
1406 struct anqp_query_info *qi)
1410 if (end - pos < 4) {
1411 wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
1416 oui = WPA_GET_BE24(pos);
1418 if (oui != OUI_WFA) {
1419 wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
1427 rx_anqp_vendor_specific_p2p(hapd, qi);
1429 #endif /* CONFIG_P2P */
1431 case HS20_ANQP_OUI_TYPE:
1432 rx_anqp_vendor_specific_hs20(hapd, pos + 1, end, qi);
1434 #endif /* CONFIG_HS20 */
1436 case MBO_ANQP_OUI_TYPE:
1437 rx_anqp_vendor_specific_mbo(hapd, pos + 1, end, qi);
1439 #endif /* CONFIG_MBO */
1441 wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
1448 static void gas_serv_req_local_processing(struct hostapd_data *hapd,
1449 const u8 *sa, u8 dialog_token,
1450 struct anqp_query_info *qi, int prot,
1453 struct wpabuf *buf, *tx_buf;
1455 buf = gas_serv_build_gas_resp_payload(hapd, qi->request,
1456 qi->home_realm_query,
1457 qi->home_realm_query_len,
1458 qi->icon_name, qi->icon_name_len,
1459 qi->extra_req, qi->num_extra_req);
1460 wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
1465 if (wpabuf_len(buf) == 0 && qi->p2p_sd) {
1466 wpa_printf(MSG_DEBUG,
1467 "ANQP: Do not send response to P2P SD from generic GAS service (P2P SD implementation will process this)");
1471 #endif /* CONFIG_P2P */
1473 if (wpabuf_len(buf) > hapd->conf->gas_frag_limit ||
1474 hapd->conf->gas_comeback_delay) {
1475 struct gas_dialog_info *di;
1476 u16 comeback_delay = 1;
1478 if (hapd->conf->gas_comeback_delay) {
1479 /* Testing - allow overriding of the delay value */
1480 comeback_delay = hapd->conf->gas_comeback_delay;
1483 wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in "
1484 "initial response - use GAS comeback");
1485 di = gas_dialog_create(hapd, sa, dialog_token);
1487 wpa_printf(MSG_INFO, "ANQP: Could not create dialog "
1488 "for " MACSTR " (dialog token %u)",
1489 MAC2STR(sa), dialog_token);
1491 tx_buf = gas_anqp_build_initial_resp_buf(
1492 dialog_token, WLAN_STATUS_UNSPECIFIED_FAILURE,
1497 di->sd_resp_pos = 0;
1498 tx_buf = gas_anqp_build_initial_resp_buf(
1499 dialog_token, WLAN_STATUS_SUCCESS,
1500 comeback_delay, NULL);
1503 wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)");
1504 tx_buf = gas_anqp_build_initial_resp_buf(
1505 dialog_token, WLAN_STATUS_SUCCESS, 0, buf);
1511 convert_to_protected_dual(tx_buf);
1513 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
1514 wpabuf_head(tx_buf),
1515 wpabuf_len(tx_buf));
1517 hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
1518 wpabuf_head(tx_buf),
1519 wpabuf_len(tx_buf));
1520 wpabuf_free(tx_buf);
1525 static void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
1526 const u8 *sa, u8 dialog_token,
1527 int prot, struct wpabuf *buf)
1529 struct wpabuf *tx_buf;
1531 if (wpabuf_len(buf) > hapd->conf->gas_frag_limit ||
1532 hapd->conf->gas_comeback_delay) {
1533 struct gas_dialog_info *di;
1534 u16 comeback_delay = 1;
1536 if (hapd->conf->gas_comeback_delay) {
1537 /* Testing - allow overriding of the delay value */
1538 comeback_delay = hapd->conf->gas_comeback_delay;
1541 wpa_printf(MSG_DEBUG,
1542 "DPP: Too long response to fit in initial response - use GAS comeback");
1543 di = gas_dialog_create(hapd, sa, dialog_token);
1545 wpa_printf(MSG_INFO, "DPP: Could not create dialog for "
1546 MACSTR " (dialog token %u)",
1547 MAC2STR(sa), dialog_token);
1549 tx_buf = gas_build_initial_resp(
1550 dialog_token, WLAN_STATUS_UNSPECIFIED_FAILURE,
1553 gas_serv_write_dpp_adv_proto(tx_buf);
1557 di->sd_resp_pos = 0;
1558 tx_buf = gas_build_initial_resp(
1559 dialog_token, WLAN_STATUS_SUCCESS,
1560 comeback_delay, 10);
1562 gas_serv_write_dpp_adv_proto(tx_buf);
1565 wpa_printf(MSG_DEBUG,
1566 "DPP: GAS Initial response (no comeback)");
1567 tx_buf = gas_build_initial_resp(
1568 dialog_token, WLAN_STATUS_SUCCESS, 0,
1569 10 + 2 + wpabuf_len(buf));
1571 gas_serv_write_dpp_adv_proto(tx_buf);
1572 wpabuf_put_le16(tx_buf, wpabuf_len(buf));
1573 wpabuf_put_buf(tx_buf, buf);
1574 hostapd_dpp_gas_status_handler(hapd, 1);
1581 convert_to_protected_dual(tx_buf);
1582 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
1583 wpabuf_head(tx_buf),
1584 wpabuf_len(tx_buf));
1585 wpabuf_free(tx_buf);
1587 #endif /* CONFIG_DPP */
1590 static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
1592 const u8 *data, size_t len, int prot,
1595 const u8 *pos = data;
1596 const u8 *end = data + len;
1600 struct anqp_query_info qi;
1601 const u8 *adv_proto;
1604 #endif /* CONFIG_DPP */
1609 os_memset(&qi, 0, sizeof(qi));
1611 dialog_token = *pos++;
1612 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
1613 "GAS: GAS Initial Request from " MACSTR " (dialog token %u) ",
1614 MAC2STR(sa), dialog_token);
1616 if (*pos != WLAN_EID_ADV_PROTO) {
1617 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
1618 "GAS: Unexpected IE in GAS Initial Request: %u", *pos);
1624 if (slen > end - pos || slen < 2) {
1625 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
1626 "GAS: Invalid IE in GAS Initial Request");
1630 pos++; /* skip QueryRespLenLimit and PAME-BI */
1633 if (slen == 8 && *pos == WLAN_EID_VENDOR_SPECIFIC &&
1634 pos[1] == 5 && WPA_GET_BE24(&pos[2]) == OUI_WFA &&
1635 pos[5] == DPP_OUI_TYPE && pos[6] == 0x01) {
1636 wpa_printf(MSG_DEBUG, "DPP: Configuration Request");
1639 #endif /* CONFIG_DPP */
1641 if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
1643 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
1644 "GAS: Unsupported GAS advertisement protocol id %u",
1647 return; /* Invalid source address - drop silently */
1648 buf = gas_build_initial_resp(
1649 dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED,
1653 wpabuf_put_data(buf, adv_proto, 2 + slen);
1654 wpabuf_put_le16(buf, 0); /* Query Response Length */
1656 convert_to_protected_dual(buf);
1658 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
1662 hostapd_drv_send_action_addr3_ap(hapd,
1663 hapd->iface->freq, 0,
1664 sa, wpabuf_head(buf),
1674 slen = WPA_GET_LE16(pos);
1676 if (slen > end - pos)
1684 msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen);
1687 gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg);
1690 #endif /* CONFIG_DPP */
1692 /* ANQP Query Request */
1699 info_id = WPA_GET_LE16(pos);
1701 elen = WPA_GET_LE16(pos);
1704 if (elen > end - pos) {
1705 wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
1710 case ANQP_QUERY_LIST:
1711 rx_anqp_query_list(hapd, pos, pos + elen, &qi);
1713 case ANQP_VENDOR_SPECIFIC:
1714 rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi);
1717 wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
1718 "Request element %u", info_id);
1725 gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot,
1730 static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
1732 const u8 *data, size_t len, int prot,
1735 struct gas_dialog_info *dialog;
1736 struct wpabuf *buf, *tx_buf;
1741 wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len);
1744 dialog_token = *data;
1745 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u",
1748 dialog = gas_serv_dialog_find(hapd, sa, dialog_token);
1750 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD "
1751 "response fragment for " MACSTR " dialog token %u",
1752 MAC2STR(sa), dialog_token);
1755 return; /* Invalid source address - drop silently */
1756 tx_buf = gas_anqp_build_comeback_resp_buf(
1757 dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0,
1764 frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
1765 if (frag_len > hapd->conf->gas_frag_limit) {
1766 frag_len = hapd->conf->gas_frag_limit;
1769 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
1770 (unsigned int) frag_len);
1771 buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
1772 dialog->sd_resp_pos, frag_len);
1774 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
1776 gas_serv_dialog_clear(dialog);
1781 tx_buf = gas_build_comeback_resp(dialog_token,
1782 WLAN_STATUS_SUCCESS,
1783 dialog->sd_frag_id, more, 0,
1786 gas_serv_write_dpp_adv_proto(tx_buf);
1787 wpabuf_put_buf(tx_buf, buf);
1790 #endif /* CONFIG_DPP */
1791 tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
1792 WLAN_STATUS_SUCCESS,
1796 if (tx_buf == NULL) {
1797 gas_serv_dialog_clear(dialog);
1800 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
1801 "(frag_id %d more=%d frag_len=%d)",
1802 dialog->sd_frag_id, more, (int) frag_len);
1803 dialog->sd_frag_id++;
1804 dialog->sd_resp_pos += frag_len;
1807 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain "
1809 (int) (wpabuf_len(dialog->sd_resp) -
1810 dialog->sd_resp_pos));
1812 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
1813 "SD response sent");
1816 hostapd_dpp_gas_status_handler(hapd, 1);
1817 #endif /* CONFIG_DPP */
1818 gas_serv_dialog_clear(dialog);
1819 gas_serv_free_dialogs(hapd, sa);
1824 convert_to_protected_dual(tx_buf);
1826 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
1827 wpabuf_head(tx_buf),
1828 wpabuf_len(tx_buf));
1830 hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
1831 wpabuf_head(tx_buf),
1832 wpabuf_len(tx_buf));
1833 wpabuf_free(tx_buf);
1837 static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
1840 struct hostapd_data *hapd = ctx;
1841 const struct ieee80211_mgmt *mgmt;
1842 const u8 *sa, *data;
1843 int prot, std_addr3;
1845 mgmt = (const struct ieee80211_mgmt *) buf;
1846 if (len < IEEE80211_HDRLEN + 2)
1848 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
1849 mgmt->u.action.category != WLAN_ACTION_PROTECTED_DUAL)
1852 * Note: Public Action and Protected Dual of Public Action frames share
1853 * the same payload structure, so it is fine to use definitions of
1854 * Public Action frames to process both.
1856 prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
1858 if (hapd->conf->gas_address3 == 1)
1860 else if (hapd->conf->gas_address3 == 2)
1863 std_addr3 = is_broadcast_ether_addr(mgmt->bssid);
1864 len -= IEEE80211_HDRLEN + 1;
1865 data = buf + IEEE80211_HDRLEN + 1;
1867 case WLAN_PA_GAS_INITIAL_REQ:
1868 gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot,
1871 case WLAN_PA_GAS_COMEBACK_REQ:
1872 gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot,
1879 int gas_serv_init(struct hostapd_data *hapd)
1881 hapd->public_action_cb2 = gas_serv_rx_public_action;
1882 hapd->public_action_cb2_ctx = hapd;
1887 void gas_serv_deinit(struct hostapd_data *hapd)