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