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 "utils/eloop.h"
16 #include "ap_config.h"
17 #include "ap_drv_ops.h"
22 static void convert_to_protected_dual(struct wpabuf *msg)
24 u8 *categ = wpabuf_mhead_u8(msg);
25 *categ = WLAN_ACTION_PROTECTED_DUAL;
29 static struct gas_dialog_info *
30 gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
33 struct gas_dialog_info *dia = NULL;
36 sta = ap_get_sta(hapd, addr);
39 * We need a STA entry to be able to maintain state for
42 wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for "
44 sta = ap_sta_add(hapd, addr);
46 wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR
47 " for GAS query", MAC2STR(addr));
50 sta->flags |= WLAN_STA_GAS;
52 * The default inactivity is 300 seconds. We don't need
55 ap_sta_session_timeout(hapd, sta, 5);
57 ap_sta_replenish_timeout(hapd, sta, 5);
60 if (sta->gas_dialog == NULL) {
61 sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX *
62 sizeof(struct gas_dialog_info));
63 if (sta->gas_dialog == NULL)
67 for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) {
68 if (i == GAS_DIALOG_MAX)
70 if (sta->gas_dialog[i].valid)
72 dia = &sta->gas_dialog[i];
75 dia->dialog_token = dialog_token;
76 sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i;
80 wpa_msg(hapd->msg_ctx, MSG_ERROR, "ANQP: Could not create dialog for "
81 MACSTR " dialog_token %u. Consider increasing "
82 "GAS_DIALOG_MAX.", MAC2STR(addr), dialog_token);
88 struct gas_dialog_info *
89 gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
95 sta = ap_get_sta(hapd, addr);
97 wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR,
101 for (i = 0; sta->gas_dialog && i < GAS_DIALOG_MAX; i++) {
102 if (sta->gas_dialog[i].dialog_token != dialog_token ||
103 !sta->gas_dialog[i].valid)
105 return &sta->gas_dialog[i];
107 wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
108 MACSTR " dialog_token %u", MAC2STR(addr), dialog_token);
113 void gas_serv_dialog_clear(struct gas_dialog_info *dia)
115 wpabuf_free(dia->sd_resp);
116 os_memset(dia, 0, sizeof(*dia));
120 static void gas_serv_free_dialogs(struct hostapd_data *hapd,
123 struct sta_info *sta;
126 sta = ap_get_sta(hapd, sta_addr);
127 if (sta == NULL || sta->gas_dialog == NULL)
130 for (i = 0; i < GAS_DIALOG_MAX; i++) {
131 if (sta->gas_dialog[i].valid)
135 os_free(sta->gas_dialog);
136 sta->gas_dialog = NULL;
141 static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
146 len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
147 wpabuf_put_be24(buf, OUI_WFA);
148 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
149 wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
150 wpabuf_put_u8(buf, 0); /* Reserved */
151 wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
152 if (hapd->conf->hs20_oper_friendly_name)
153 wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
154 if (hapd->conf->hs20_wan_metrics)
155 wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
156 if (hapd->conf->hs20_connection_capability)
157 wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
158 if (hapd->conf->nai_realm_data)
159 wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
160 if (hapd->conf->hs20_operating_class)
161 wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
162 gas_anqp_set_element_len(buf, len);
164 #endif /* CONFIG_HS20 */
167 static void anqp_add_capab_list(struct hostapd_data *hapd,
172 len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
173 wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
174 if (hapd->conf->venue_name)
175 wpabuf_put_le16(buf, ANQP_VENUE_NAME);
176 if (hapd->conf->network_auth_type)
177 wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
178 if (hapd->conf->roaming_consortium)
179 wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
180 if (hapd->conf->ipaddr_type_configured)
181 wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
182 if (hapd->conf->nai_realm_data)
183 wpabuf_put_le16(buf, ANQP_NAI_REALM);
184 if (hapd->conf->anqp_3gpp_cell_net)
185 wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
186 if (hapd->conf->domain_name)
187 wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
189 anqp_add_hs_capab_list(hapd, buf);
190 #endif /* CONFIG_HS20 */
191 gas_anqp_set_element_len(buf, len);
195 static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
197 if (hapd->conf->venue_name) {
200 len = gas_anqp_add_element(buf, ANQP_VENUE_NAME);
201 wpabuf_put_u8(buf, hapd->conf->venue_group);
202 wpabuf_put_u8(buf, hapd->conf->venue_type);
203 for (i = 0; i < hapd->conf->venue_name_count; i++) {
204 struct hostapd_lang_string *vn;
205 vn = &hapd->conf->venue_name[i];
206 wpabuf_put_u8(buf, 3 + vn->name_len);
207 wpabuf_put_data(buf, vn->lang, 3);
208 wpabuf_put_data(buf, vn->name, vn->name_len);
210 gas_anqp_set_element_len(buf, len);
215 static void anqp_add_network_auth_type(struct hostapd_data *hapd,
218 if (hapd->conf->network_auth_type) {
219 wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
220 wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
221 wpabuf_put_data(buf, hapd->conf->network_auth_type,
222 hapd->conf->network_auth_type_len);
227 static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
233 len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
234 for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
235 struct hostapd_roaming_consortium *rc;
236 rc = &hapd->conf->roaming_consortium[i];
237 wpabuf_put_u8(buf, rc->len);
238 wpabuf_put_data(buf, rc->oi, rc->len);
240 gas_anqp_set_element_len(buf, len);
244 static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
247 if (hapd->conf->ipaddr_type_configured) {
248 wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
249 wpabuf_put_le16(buf, 1);
250 wpabuf_put_u8(buf, hapd->conf->ipaddr_type_availability);
255 static void anqp_add_nai_realm_eap(struct wpabuf *buf,
256 struct hostapd_nai_realm_data *realm)
260 wpabuf_put_u8(buf, realm->eap_method_count);
262 for (i = 0; i < realm->eap_method_count; i++) {
263 struct hostapd_nai_realm_eap *eap = &realm->eap_method[i];
264 wpabuf_put_u8(buf, 2 + (3 * eap->num_auths));
265 wpabuf_put_u8(buf, eap->eap_method);
266 wpabuf_put_u8(buf, eap->num_auths);
267 for (j = 0; j < eap->num_auths; j++) {
268 wpabuf_put_u8(buf, eap->auth_id[j]);
269 wpabuf_put_u8(buf, 1);
270 wpabuf_put_u8(buf, eap->auth_val[j]);
276 static void anqp_add_nai_realm_data(struct wpabuf *buf,
277 struct hostapd_nai_realm_data *realm,
278 unsigned int realm_idx)
282 wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx],
283 (int) os_strlen(realm->realm[realm_idx]));
284 realm_data_len = wpabuf_put(buf, 2);
285 wpabuf_put_u8(buf, realm->encoding);
286 wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx]));
287 wpabuf_put_str(buf, realm->realm[realm_idx]);
288 anqp_add_nai_realm_eap(buf, realm);
289 gas_anqp_set_element_len(buf, realm_data_len);
293 static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
295 const u8 *home_realm,
296 size_t home_realm_len)
298 unsigned int i, j, k;
299 u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len;
300 struct hostapd_nai_realm_data *realm;
301 const u8 *pos, *realm_name, *end;
303 unsigned int realm_data_idx;
304 unsigned int realm_idx;
308 end = pos + home_realm_len;
310 wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
311 home_realm, home_realm_len);
316 for (i = 0; i < num_realms && num_matching < 10; i++) {
318 wpa_hexdump(MSG_DEBUG,
319 "Truncated NAI Home Realm Query",
320 home_realm, home_realm_len);
325 if (pos + realm_len > end) {
326 wpa_hexdump(MSG_DEBUG,
327 "Truncated NAI Home Realm Query",
328 home_realm, home_realm_len);
332 for (j = 0; j < hapd->conf->nai_realm_count &&
333 num_matching < 10; j++) {
334 const u8 *rpos, *rend;
335 realm = &hapd->conf->nai_realm_data[j];
336 if (encoding != realm->encoding)
340 while (rpos < realm_name + realm_len &&
343 rend < realm_name + realm_len; rend++) {
347 for (k = 0; k < MAX_NAI_REALMS &&
349 num_matching < 10; k++) {
350 if ((int) os_strlen(realm->realm[k]) !=
352 os_strncmp((char *) rpos,
356 matches[num_matching].realm_data_idx =
358 matches[num_matching].realm_idx = k;
367 realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
368 wpabuf_put_le16(buf, num_matching);
371 * There are two ways to format. 1. each realm in a NAI Realm Data unit
372 * 2. all realms that share the same EAP methods in a NAI Realm Data
373 * unit. The first format is likely to be bigger in size than the
374 * second, but may be easier to parse and process by the receiver.
376 for (i = 0; i < num_matching; i++) {
377 wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d",
378 matches[i].realm_data_idx, matches[i].realm_idx);
379 realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx];
380 anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx);
382 gas_anqp_set_element_len(buf, realm_list_len);
387 static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
388 const u8 *home_realm, size_t home_realm_len,
389 int nai_realm, int nai_home_realm)
391 if (nai_realm && hapd->conf->nai_realm_data) {
394 len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
395 wpabuf_put_le16(buf, hapd->conf->nai_realm_count);
396 for (i = 0; i < hapd->conf->nai_realm_count; i++) {
397 u8 *realm_data_len, *realm_len;
398 struct hostapd_nai_realm_data *realm;
400 realm = &hapd->conf->nai_realm_data[i];
401 realm_data_len = wpabuf_put(buf, 2);
402 wpabuf_put_u8(buf, realm->encoding);
403 realm_len = wpabuf_put(buf, 1);
404 for (j = 0; realm->realm[j]; j++) {
406 wpabuf_put_u8(buf, ';');
407 wpabuf_put_str(buf, realm->realm[j]);
409 *realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1;
410 anqp_add_nai_realm_eap(buf, realm);
411 gas_anqp_set_element_len(buf, realm_data_len);
413 gas_anqp_set_element_len(buf, len);
414 } else if (nai_home_realm && hapd->conf->nai_realm_data) {
415 hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
421 static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
424 if (hapd->conf->anqp_3gpp_cell_net) {
425 wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
427 hapd->conf->anqp_3gpp_cell_net_len);
428 wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net,
429 hapd->conf->anqp_3gpp_cell_net_len);
434 static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
436 if (hapd->conf->domain_name) {
437 wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
438 wpabuf_put_le16(buf, hapd->conf->domain_name_len);
439 wpabuf_put_data(buf, hapd->conf->domain_name,
440 hapd->conf->domain_name_len);
447 static void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
450 if (hapd->conf->hs20_oper_friendly_name) {
453 len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
454 wpabuf_put_be24(buf, OUI_WFA);
455 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
456 wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
457 wpabuf_put_u8(buf, 0); /* Reserved */
458 for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++)
460 struct hostapd_lang_string *vn;
461 vn = &hapd->conf->hs20_oper_friendly_name[i];
462 wpabuf_put_u8(buf, 3 + vn->name_len);
463 wpabuf_put_data(buf, vn->lang, 3);
464 wpabuf_put_data(buf, vn->name, vn->name_len);
466 gas_anqp_set_element_len(buf, len);
471 static void anqp_add_wan_metrics(struct hostapd_data *hapd,
474 if (hapd->conf->hs20_wan_metrics) {
475 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
476 wpabuf_put_be24(buf, OUI_WFA);
477 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
478 wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
479 wpabuf_put_u8(buf, 0); /* Reserved */
480 wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13);
481 gas_anqp_set_element_len(buf, len);
486 static void anqp_add_connection_capability(struct hostapd_data *hapd,
489 if (hapd->conf->hs20_connection_capability) {
490 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
491 wpabuf_put_be24(buf, OUI_WFA);
492 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
493 wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
494 wpabuf_put_u8(buf, 0); /* Reserved */
495 wpabuf_put_data(buf, hapd->conf->hs20_connection_capability,
496 hapd->conf->hs20_connection_capability_len);
497 gas_anqp_set_element_len(buf, len);
502 static void anqp_add_operating_class(struct hostapd_data *hapd,
505 if (hapd->conf->hs20_operating_class) {
506 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
507 wpabuf_put_be24(buf, OUI_WFA);
508 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
509 wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
510 wpabuf_put_u8(buf, 0); /* Reserved */
511 wpabuf_put_data(buf, hapd->conf->hs20_operating_class,
512 hapd->conf->hs20_operating_class_len);
513 gas_anqp_set_element_len(buf, len);
517 #endif /* CONFIG_HS20 */
520 static struct wpabuf *
521 gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
522 unsigned int request,
523 struct gas_dialog_info *di,
524 const u8 *home_realm, size_t home_realm_len)
528 buf = wpabuf_alloc(1400);
532 if (request & ANQP_REQ_CAPABILITY_LIST)
533 anqp_add_capab_list(hapd, buf);
534 if (request & ANQP_REQ_VENUE_NAME)
535 anqp_add_venue_name(hapd, buf);
536 if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
537 anqp_add_network_auth_type(hapd, buf);
538 if (request & ANQP_REQ_ROAMING_CONSORTIUM)
539 anqp_add_roaming_consortium(hapd, buf);
540 if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY)
541 anqp_add_ip_addr_type_availability(hapd, buf);
542 if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
543 anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len,
544 request & ANQP_REQ_NAI_REALM,
545 request & ANQP_REQ_NAI_HOME_REALM);
546 if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
547 anqp_add_3gpp_cellular_network(hapd, buf);
548 if (request & ANQP_REQ_DOMAIN_NAME)
549 anqp_add_domain_name(hapd, buf);
552 if (request & ANQP_REQ_HS_CAPABILITY_LIST)
553 anqp_add_hs_capab_list(hapd, buf);
554 if (request & ANQP_REQ_OPERATOR_FRIENDLY_NAME)
555 anqp_add_operator_friendly_name(hapd, buf);
556 if (request & ANQP_REQ_WAN_METRICS)
557 anqp_add_wan_metrics(hapd, buf);
558 if (request & ANQP_REQ_CONNECTION_CAPABILITY)
559 anqp_add_connection_capability(hapd, buf);
560 if (request & ANQP_REQ_OPERATING_CLASS)
561 anqp_add_operating_class(hapd, buf);
562 #endif /* CONFIG_HS20 */
568 static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx)
570 struct gas_dialog_info *dia = eloop_data;
572 wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for "
573 "dialog token %d", dia->dialog_token);
575 gas_serv_dialog_clear(dia);
579 struct anqp_query_info {
580 unsigned int request;
581 unsigned int remote_request;
582 const u8 *home_realm_query;
583 size_t home_realm_query_len;
588 static void set_anqp_req(unsigned int bit, const char *name, int local,
589 unsigned int remote, u16 remote_delay,
590 struct anqp_query_info *qi)
594 wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name);
595 } else if (bit & remote) {
596 wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name);
597 qi->remote_request |= bit;
598 if (remote_delay > qi->remote_delay)
599 qi->remote_delay = remote_delay;
601 wpa_printf(MSG_DEBUG, "ANQP: %s not available", name);
606 static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
607 struct anqp_query_info *qi)
610 case ANQP_CAPABILITY_LIST:
611 set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0,
614 case ANQP_VENUE_NAME:
615 set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
616 hapd->conf->venue_name != NULL, 0, 0, qi);
618 case ANQP_NETWORK_AUTH_TYPE:
619 set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
620 hapd->conf->network_auth_type != NULL,
623 case ANQP_ROAMING_CONSORTIUM:
624 set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
625 hapd->conf->roaming_consortium != NULL, 0, 0, qi);
627 case ANQP_IP_ADDR_TYPE_AVAILABILITY:
628 set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY,
629 "IP Addr Type Availability",
630 hapd->conf->ipaddr_type_configured,
634 set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm",
635 hapd->conf->nai_realm_data != NULL,
638 case ANQP_3GPP_CELLULAR_NETWORK:
639 set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
640 "3GPP Cellular Network",
641 hapd->conf->anqp_3gpp_cell_net != NULL,
644 case ANQP_DOMAIN_NAME:
645 set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
646 hapd->conf->domain_name != NULL,
650 wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
657 static void rx_anqp_query_list(struct hostapd_data *hapd,
658 const u8 *pos, const u8 *end,
659 struct anqp_query_info *qi)
661 wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
662 (unsigned int) (end - pos) / 2);
664 while (pos + 2 <= end) {
665 rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
673 static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
674 struct anqp_query_info *qi)
677 case HS20_STYPE_CAPABILITY_LIST:
678 set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List",
681 case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
682 set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME,
683 "Operator Friendly Name",
684 hapd->conf->hs20_oper_friendly_name != NULL,
687 case HS20_STYPE_WAN_METRICS:
688 set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics",
689 hapd->conf->hs20_wan_metrics != NULL,
692 case HS20_STYPE_CONNECTION_CAPABILITY:
693 set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY,
694 "Connection Capability",
695 hapd->conf->hs20_connection_capability != NULL,
698 case HS20_STYPE_OPERATING_CLASS:
699 set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class",
700 hapd->conf->hs20_operating_class != NULL,
704 wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
711 static void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd,
712 const u8 *pos, const u8 *end,
713 struct anqp_query_info *qi)
715 qi->request |= ANQP_REQ_NAI_HOME_REALM;
716 qi->home_realm_query = pos;
717 qi->home_realm_query_len = end - pos;
718 if (hapd->conf->nai_realm_data != NULL) {
719 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query "
722 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not "
728 static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
729 const u8 *pos, const u8 *end,
730 struct anqp_query_info *qi)
736 wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
741 oui = WPA_GET_BE24(pos);
743 if (oui != OUI_WFA) {
744 wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
749 if (*pos != HS20_ANQP_OUI_TYPE) {
750 wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
760 pos++; /* Reserved */
762 case HS20_STYPE_QUERY_LIST:
763 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List");
765 rx_anqp_hs_query_list(hapd, *pos, qi);
769 case HS20_STYPE_NAI_HOME_REALM_QUERY:
770 rx_anqp_hs_nai_home_realm(hapd, pos, end, qi);
773 wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype "
779 #endif /* CONFIG_HS20 */
782 static void gas_serv_req_local_processing(struct hostapd_data *hapd,
783 const u8 *sa, u8 dialog_token,
784 struct anqp_query_info *qi, int prot)
786 struct wpabuf *buf, *tx_buf;
788 buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL,
789 qi->home_realm_query,
790 qi->home_realm_query_len);
791 wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
796 if (wpabuf_len(buf) > hapd->gas_frag_limit ||
797 hapd->conf->gas_comeback_delay) {
798 struct gas_dialog_info *di;
799 u16 comeback_delay = 1;
801 if (hapd->conf->gas_comeback_delay) {
802 /* Testing - allow overriding of the delay value */
803 comeback_delay = hapd->conf->gas_comeback_delay;
806 wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in "
807 "initial response - use GAS comeback");
808 di = gas_dialog_create(hapd, sa, dialog_token);
810 wpa_printf(MSG_INFO, "ANQP: Could not create dialog "
811 "for " MACSTR " (dialog token %u)",
812 MAC2STR(sa), dialog_token);
819 tx_buf = gas_anqp_build_initial_resp_buf(
820 dialog_token, WLAN_STATUS_SUCCESS, comeback_delay,
823 wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)");
824 tx_buf = gas_anqp_build_initial_resp_buf(
825 dialog_token, WLAN_STATUS_SUCCESS, 0, buf);
831 convert_to_protected_dual(tx_buf);
832 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
833 wpabuf_head(tx_buf), wpabuf_len(tx_buf));
838 static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
840 const u8 *data, size_t len, int prot)
842 const u8 *pos = data;
843 const u8 *end = data + len;
847 struct anqp_query_info qi;
853 os_memset(&qi, 0, sizeof(qi));
855 dialog_token = *pos++;
856 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
857 "GAS: GAS Initial Request from " MACSTR " (dialog token %u) ",
858 MAC2STR(sa), dialog_token);
860 if (*pos != WLAN_EID_ADV_PROTO) {
861 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
862 "GAS: Unexpected IE in GAS Initial Request: %u", *pos);
869 if (next > end || slen < 2) {
870 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
871 "GAS: Invalid IE in GAS Initial Request");
874 pos++; /* skip QueryRespLenLimit and PAME-BI */
876 if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
878 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
879 "GAS: Unsupported GAS advertisement protocol id %u",
882 return; /* Invalid source address - drop silently */
883 buf = gas_build_initial_resp(
884 dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED,
888 wpabuf_put_data(buf, adv_proto, 2 + slen);
889 wpabuf_put_le16(buf, 0); /* Query Response Length */
891 convert_to_protected_dual(buf);
892 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
893 wpabuf_head(buf), wpabuf_len(buf));
902 slen = WPA_GET_LE16(pos);
904 if (pos + slen > end)
908 /* ANQP Query Request */
915 info_id = WPA_GET_LE16(pos);
917 elen = WPA_GET_LE16(pos);
920 if (pos + elen > end) {
921 wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
926 case ANQP_QUERY_LIST:
927 rx_anqp_query_list(hapd, pos, pos + elen, &qi);
930 case ANQP_VENDOR_SPECIFIC:
931 rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi);
933 #endif /* CONFIG_HS20 */
935 wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
936 "Request element %u", info_id);
943 gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot);
947 void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
948 struct gas_dialog_info *dialog)
950 struct wpabuf *buf, *tx_buf;
951 u8 dialog_token = dialog->dialog_token;
954 if (dialog->sd_resp == NULL) {
955 buf = gas_serv_build_gas_resp_payload(hapd,
956 dialog->all_requested,
958 wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
961 goto tx_gas_response_done;
962 dialog->sd_resp = buf;
963 dialog->sd_resp_pos = 0;
965 frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
966 if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay ||
967 hapd->conf->gas_comeback_delay) {
968 u16 comeback_delay_tus = dialog->comeback_delay +
969 GAS_SERV_COMEBACK_DELAY_FUDGE;
970 u32 comeback_delay_secs, comeback_delay_usecs;
972 if (hapd->conf->gas_comeback_delay) {
973 /* Testing - allow overriding of the delay value */
974 comeback_delay_tus = hapd->conf->gas_comeback_delay;
977 wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit "
978 "%u) and comeback delay %u, "
979 "requesting comebacks", (unsigned int) frag_len,
980 (unsigned int) hapd->gas_frag_limit,
981 dialog->comeback_delay);
982 tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
987 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
988 "GAS: Tx GAS Initial Resp (comeback = 10TU)");
990 convert_to_protected_dual(tx_buf);
991 hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
998 /* start a timer of 1.5 * comeback-delay */
999 comeback_delay_tus = comeback_delay_tus +
1000 (comeback_delay_tus / 2);
1001 comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000;
1002 comeback_delay_usecs = (comeback_delay_tus * 1024) -
1003 (comeback_delay_secs * 1000000);
1004 eloop_register_timeout(comeback_delay_secs,
1005 comeback_delay_usecs,
1006 gas_serv_clear_cached_ies, dialog,
1008 goto tx_gas_response_done;
1011 buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
1012 dialog->sd_resp_pos, frag_len);
1014 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation "
1016 goto tx_gas_response_done;
1018 tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
1019 WLAN_STATUS_SUCCESS, 0, buf);
1022 goto tx_gas_response_done;
1023 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial "
1024 "Response (frag_id %d frag_len %d)",
1025 dialog->sd_frag_id, (int) frag_len);
1026 dialog->sd_frag_id++;
1029 convert_to_protected_dual(tx_buf);
1030 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
1031 wpabuf_head(tx_buf), wpabuf_len(tx_buf));
1032 wpabuf_free(tx_buf);
1033 tx_gas_response_done:
1034 gas_serv_clear_cached_ies(dialog, NULL);
1038 static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
1040 const u8 *data, size_t len, int prot)
1042 struct gas_dialog_info *dialog;
1043 struct wpabuf *buf, *tx_buf;
1048 wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len);
1051 dialog_token = *data;
1052 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u",
1055 dialog = gas_serv_dialog_find(hapd, sa, dialog_token);
1057 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD "
1058 "response fragment for " MACSTR " dialog token %u",
1059 MAC2STR(sa), dialog_token);
1062 return; /* Invalid source address - drop silently */
1063 tx_buf = gas_anqp_build_comeback_resp_buf(
1064 dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0,
1071 if (dialog->sd_resp == NULL) {
1072 wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x",
1073 dialog->requested, dialog->received);
1074 if ((dialog->requested & dialog->received) !=
1075 dialog->requested) {
1076 wpa_printf(MSG_DEBUG, "GAS: Did not receive response "
1077 "from remote processing");
1078 gas_serv_dialog_clear(dialog);
1079 tx_buf = gas_anqp_build_comeback_resp_buf(
1081 WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0,
1088 buf = gas_serv_build_gas_resp_payload(hapd,
1089 dialog->all_requested,
1091 wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
1094 goto rx_gas_comeback_req_done;
1095 dialog->sd_resp = buf;
1096 dialog->sd_resp_pos = 0;
1098 frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
1099 if (frag_len > hapd->gas_frag_limit) {
1100 frag_len = hapd->gas_frag_limit;
1103 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
1104 (unsigned int) frag_len);
1105 buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
1106 dialog->sd_resp_pos, frag_len);
1108 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
1110 goto rx_gas_comeback_req_done;
1112 tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
1113 WLAN_STATUS_SUCCESS,
1118 goto rx_gas_comeback_req_done;
1119 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
1120 "(frag_id %d more=%d frag_len=%d)",
1121 dialog->sd_frag_id, more, (int) frag_len);
1122 dialog->sd_frag_id++;
1123 dialog->sd_resp_pos += frag_len;
1126 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain "
1128 (int) (wpabuf_len(dialog->sd_resp) -
1129 dialog->sd_resp_pos));
1131 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
1132 "SD response sent");
1133 gas_serv_dialog_clear(dialog);
1134 gas_serv_free_dialogs(hapd, sa);
1139 convert_to_protected_dual(tx_buf);
1140 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
1141 wpabuf_head(tx_buf), wpabuf_len(tx_buf));
1142 wpabuf_free(tx_buf);
1145 rx_gas_comeback_req_done:
1146 gas_serv_clear_cached_ies(dialog, NULL);
1150 static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
1153 struct hostapd_data *hapd = ctx;
1154 const struct ieee80211_mgmt *mgmt;
1156 const u8 *sa, *data;
1159 mgmt = (const struct ieee80211_mgmt *) buf;
1160 hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
1163 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
1164 mgmt->u.action.category != WLAN_ACTION_PROTECTED_DUAL)
1167 * Note: Public Action and Protected Dual of Public Action frames share
1168 * the same payload structure, so it is fine to use definitions of
1169 * Public Action frames to process both.
1171 prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
1174 data = &mgmt->u.action.u.public_action.action;
1176 case WLAN_PA_GAS_INITIAL_REQ:
1177 gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot);
1179 case WLAN_PA_GAS_COMEBACK_REQ:
1180 gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot);
1186 int gas_serv_init(struct hostapd_data *hapd)
1188 hapd->public_action_cb2 = gas_serv_rx_public_action;
1189 hapd->public_action_cb2_ctx = hapd;
1190 hapd->gas_frag_limit = 1400;
1191 if (hapd->conf->gas_frag_limit > 0)
1192 hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
1197 void gas_serv_deinit(struct hostapd_data *hapd)