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