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 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
,
1688 gas_serv_req_dpp_processing(hapd
, sa
, dialog_token
, prot
, msg
);
1691 #endif /* CONFIG_DPP */
1693 /* ANQP Query Request */
1700 info_id
= WPA_GET_LE16(pos
);
1702 elen
= WPA_GET_LE16(pos
);
1705 if (elen
> end
- pos
) {
1706 wpa_printf(MSG_DEBUG
, "ANQP: Invalid Query Request");
1711 case ANQP_QUERY_LIST
:
1712 rx_anqp_query_list(hapd
, pos
, pos
+ elen
, &qi
);
1714 case ANQP_VENDOR_SPECIFIC
:
1715 rx_anqp_vendor_specific(hapd
, pos
, pos
+ elen
, &qi
);
1718 wpa_printf(MSG_DEBUG
, "ANQP: Unsupported Query "
1719 "Request element %u", info_id
);
1726 gas_serv_req_local_processing(hapd
, sa
, dialog_token
, &qi
, prot
,
1731 static void gas_serv_rx_gas_comeback_req(struct hostapd_data
*hapd
,
1733 const u8
*data
, size_t len
, int prot
,
1736 struct gas_dialog_info
*dialog
;
1737 struct wpabuf
*buf
, *tx_buf
;
1742 wpa_hexdump(MSG_DEBUG
, "GAS: RX GAS Comeback Request", data
, len
);
1745 dialog_token
= *data
;
1746 wpa_msg(hapd
->msg_ctx
, MSG_DEBUG
, "GAS: Dialog Token: %u",
1749 dialog
= gas_serv_dialog_find(hapd
, sa
, dialog_token
);
1751 wpa_msg(hapd
->msg_ctx
, MSG_DEBUG
, "GAS: No pending SD "
1752 "response fragment for " MACSTR
" dialog token %u",
1753 MAC2STR(sa
), dialog_token
);
1756 return; /* Invalid source address - drop silently */
1757 tx_buf
= gas_anqp_build_comeback_resp_buf(
1758 dialog_token
, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ
, 0, 0,
1765 frag_len
= wpabuf_len(dialog
->sd_resp
) - dialog
->sd_resp_pos
;
1766 if (frag_len
> hapd
->conf
->gas_frag_limit
) {
1767 frag_len
= hapd
->conf
->gas_frag_limit
;
1770 wpa_msg(hapd
->msg_ctx
, MSG_DEBUG
, "GAS: resp frag_len %u",
1771 (unsigned int) frag_len
);
1772 buf
= wpabuf_alloc_copy(wpabuf_head_u8(dialog
->sd_resp
) +
1773 dialog
->sd_resp_pos
, frag_len
);
1775 wpa_msg(hapd
->msg_ctx
, MSG_DEBUG
, "GAS: Failed to allocate "
1777 gas_serv_dialog_clear(dialog
);
1782 tx_buf
= gas_build_comeback_resp(dialog_token
,
1783 WLAN_STATUS_SUCCESS
,
1784 dialog
->sd_frag_id
, more
, 0,
1787 gas_serv_write_dpp_adv_proto(tx_buf
);
1788 wpabuf_put_buf(tx_buf
, buf
);
1791 #endif /* CONFIG_DPP */
1792 tx_buf
= gas_anqp_build_comeback_resp_buf(dialog_token
,
1793 WLAN_STATUS_SUCCESS
,
1797 if (tx_buf
== NULL
) {
1798 gas_serv_dialog_clear(dialog
);
1801 wpa_msg(hapd
->msg_ctx
, MSG_DEBUG
, "GAS: Tx GAS Comeback Response "
1802 "(frag_id %d more=%d frag_len=%d)",
1803 dialog
->sd_frag_id
, more
, (int) frag_len
);
1804 dialog
->sd_frag_id
++;
1805 dialog
->sd_resp_pos
+= frag_len
;
1808 wpa_msg(hapd
->msg_ctx
, MSG_DEBUG
, "GAS: %d more bytes remain "
1810 (int) (wpabuf_len(dialog
->sd_resp
) -
1811 dialog
->sd_resp_pos
));
1813 wpa_msg(hapd
->msg_ctx
, MSG_DEBUG
, "GAS: All fragments of "
1814 "SD response sent");
1817 hostapd_dpp_gas_status_handler(hapd
, 1);
1818 #endif /* CONFIG_DPP */
1819 gas_serv_dialog_clear(dialog
);
1820 gas_serv_free_dialogs(hapd
, sa
);
1825 convert_to_protected_dual(tx_buf
);
1827 hostapd_drv_send_action(hapd
, hapd
->iface
->freq
, 0, sa
,
1828 wpabuf_head(tx_buf
),
1829 wpabuf_len(tx_buf
));
1831 hostapd_drv_send_action_addr3_ap(hapd
, hapd
->iface
->freq
, 0, sa
,
1832 wpabuf_head(tx_buf
),
1833 wpabuf_len(tx_buf
));
1834 wpabuf_free(tx_buf
);
1838 static void gas_serv_rx_public_action(void *ctx
, const u8
*buf
, size_t len
,
1841 struct hostapd_data
*hapd
= ctx
;
1842 const struct ieee80211_mgmt
*mgmt
;
1843 const u8
*sa
, *data
;
1844 int prot
, std_addr3
;
1846 mgmt
= (const struct ieee80211_mgmt
*) buf
;
1847 if (len
< IEEE80211_HDRLEN
+ 2)
1849 if (mgmt
->u
.action
.category
!= WLAN_ACTION_PUBLIC
&&
1850 mgmt
->u
.action
.category
!= WLAN_ACTION_PROTECTED_DUAL
)
1853 * Note: Public Action and Protected Dual of Public Action frames share
1854 * the same payload structure, so it is fine to use definitions of
1855 * Public Action frames to process both.
1857 prot
= mgmt
->u
.action
.category
== WLAN_ACTION_PROTECTED_DUAL
;
1859 if (hapd
->conf
->gas_address3
== 1)
1861 else if (hapd
->conf
->gas_address3
== 2)
1864 std_addr3
= is_broadcast_ether_addr(mgmt
->bssid
);
1865 len
-= IEEE80211_HDRLEN
+ 1;
1866 data
= buf
+ IEEE80211_HDRLEN
+ 1;
1868 case WLAN_PA_GAS_INITIAL_REQ
:
1869 gas_serv_rx_gas_initial_req(hapd
, sa
, data
+ 1, len
- 1, prot
,
1872 case WLAN_PA_GAS_COMEBACK_REQ
:
1873 gas_serv_rx_gas_comeback_req(hapd
, sa
, data
+ 1, len
- 1, prot
,
1880 int gas_serv_init(struct hostapd_data
*hapd
)
1882 hapd
->public_action_cb2
= gas_serv_rx_public_action
;
1883 hapd
->public_action_cb2_ctx
= hapd
;
1888 void gas_serv_deinit(struct hostapd_data
*hapd
)