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