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