gas_serv.c revision 5460547a121207cf7a99eac45e05fcdd83be3161
1/* 2 * Generic advertisement service (GAS) server 3 * Copyright (c) 2011-2012, 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 22static struct gas_dialog_info * 23gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token) 24{ 25 struct sta_info *sta; 26 struct gas_dialog_info *dia = NULL; 27 int i, j; 28 29 sta = ap_get_sta(hapd, addr); 30 if (!sta) { 31 /* 32 * We need a STA entry to be able to maintain state for 33 * the GAS query. 34 */ 35 wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for " 36 "GAS query"); 37 sta = ap_sta_add(hapd, addr); 38 if (!sta) { 39 wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR 40 " for GAS query", MAC2STR(addr)); 41 return NULL; 42 } 43 sta->flags |= WLAN_STA_GAS; 44 /* 45 * The default inactivity is 300 seconds. We don't need 46 * it to be that long. 47 */ 48 ap_sta_session_timeout(hapd, sta, 5); 49 } else { 50 ap_sta_replenish_timeout(hapd, sta, 5); 51 } 52 53 if (sta->gas_dialog == NULL) { 54 sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX * 55 sizeof(struct gas_dialog_info)); 56 if (sta->gas_dialog == NULL) 57 return NULL; 58 } 59 60 for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) { 61 if (i == GAS_DIALOG_MAX) 62 i = 0; 63 if (sta->gas_dialog[i].valid) 64 continue; 65 dia = &sta->gas_dialog[i]; 66 dia->valid = 1; 67 dia->index = i; 68 dia->dialog_token = dialog_token; 69 sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i; 70 return dia; 71 } 72 73 wpa_msg(hapd->msg_ctx, MSG_ERROR, "ANQP: Could not create dialog for " 74 MACSTR " dialog_token %u. Consider increasing " 75 "GAS_DIALOG_MAX.", MAC2STR(addr), dialog_token); 76 77 return NULL; 78} 79 80 81struct gas_dialog_info * 82gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr, 83 u8 dialog_token) 84{ 85 struct sta_info *sta; 86 int i; 87 88 sta = ap_get_sta(hapd, addr); 89 if (!sta) { 90 wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR, 91 MAC2STR(addr)); 92 return NULL; 93 } 94 for (i = 0; sta->gas_dialog && i < GAS_DIALOG_MAX; i++) { 95 if (sta->gas_dialog[i].dialog_token != dialog_token || 96 !sta->gas_dialog[i].valid) 97 continue; 98 return &sta->gas_dialog[i]; 99 } 100 wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for " 101 MACSTR " dialog_token %u", MAC2STR(addr), dialog_token); 102 return NULL; 103} 104 105 106void gas_serv_dialog_clear(struct gas_dialog_info *dia) 107{ 108 wpabuf_free(dia->sd_resp); 109 os_memset(dia, 0, sizeof(*dia)); 110} 111 112 113static void gas_serv_free_dialogs(struct hostapd_data *hapd, 114 const u8 *sta_addr) 115{ 116 struct sta_info *sta; 117 int i; 118 119 sta = ap_get_sta(hapd, sta_addr); 120 if (sta == NULL || sta->gas_dialog == NULL) 121 return; 122 123 for (i = 0; i < GAS_DIALOG_MAX; i++) { 124 if (sta->gas_dialog[i].valid) 125 return; 126 } 127 128 os_free(sta->gas_dialog); 129 sta->gas_dialog = NULL; 130} 131 132 133#ifdef CONFIG_HS20 134static void anqp_add_hs_capab_list(struct hostapd_data *hapd, 135 struct wpabuf *buf) 136{ 137 u8 *len; 138 139 len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 140 wpabuf_put_be24(buf, OUI_WFA); 141 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 142 wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST); 143 wpabuf_put_u8(buf, 0); /* Reserved */ 144 wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST); 145 if (hapd->conf->hs20_oper_friendly_name) 146 wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME); 147 if (hapd->conf->hs20_wan_metrics) 148 wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS); 149 if (hapd->conf->hs20_connection_capability) 150 wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY); 151 if (hapd->conf->nai_realm_data) 152 wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY); 153 if (hapd->conf->hs20_operating_class) 154 wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS); 155 gas_anqp_set_element_len(buf, len); 156} 157#endif /* CONFIG_HS20 */ 158 159 160static void anqp_add_capab_list(struct hostapd_data *hapd, 161 struct wpabuf *buf) 162{ 163 u8 *len; 164 165 len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST); 166 wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST); 167 if (hapd->conf->venue_name) 168 wpabuf_put_le16(buf, ANQP_VENUE_NAME); 169 if (hapd->conf->network_auth_type) 170 wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE); 171 if (hapd->conf->roaming_consortium) 172 wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM); 173 if (hapd->conf->ipaddr_type_configured) 174 wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY); 175 if (hapd->conf->nai_realm_data) 176 wpabuf_put_le16(buf, ANQP_NAI_REALM); 177 if (hapd->conf->anqp_3gpp_cell_net) 178 wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK); 179 if (hapd->conf->domain_name) 180 wpabuf_put_le16(buf, ANQP_DOMAIN_NAME); 181#ifdef CONFIG_HS20 182 anqp_add_hs_capab_list(hapd, buf); 183#endif /* CONFIG_HS20 */ 184 gas_anqp_set_element_len(buf, len); 185} 186 187 188static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf) 189{ 190 if (hapd->conf->venue_name) { 191 u8 *len; 192 unsigned int i; 193 len = gas_anqp_add_element(buf, ANQP_VENUE_NAME); 194 wpabuf_put_u8(buf, hapd->conf->venue_group); 195 wpabuf_put_u8(buf, hapd->conf->venue_type); 196 for (i = 0; i < hapd->conf->venue_name_count; i++) { 197 struct hostapd_lang_string *vn; 198 vn = &hapd->conf->venue_name[i]; 199 wpabuf_put_u8(buf, 3 + vn->name_len); 200 wpabuf_put_data(buf, vn->lang, 3); 201 wpabuf_put_data(buf, vn->name, vn->name_len); 202 } 203 gas_anqp_set_element_len(buf, len); 204 } 205} 206 207 208static void anqp_add_network_auth_type(struct hostapd_data *hapd, 209 struct wpabuf *buf) 210{ 211 if (hapd->conf->network_auth_type) { 212 wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE); 213 wpabuf_put_le16(buf, hapd->conf->network_auth_type_len); 214 wpabuf_put_data(buf, hapd->conf->network_auth_type, 215 hapd->conf->network_auth_type_len); 216 } 217} 218 219 220static void anqp_add_roaming_consortium(struct hostapd_data *hapd, 221 struct wpabuf *buf) 222{ 223 unsigned int i; 224 u8 *len; 225 226 len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM); 227 for (i = 0; i < hapd->conf->roaming_consortium_count; i++) { 228 struct hostapd_roaming_consortium *rc; 229 rc = &hapd->conf->roaming_consortium[i]; 230 wpabuf_put_u8(buf, rc->len); 231 wpabuf_put_data(buf, rc->oi, rc->len); 232 } 233 gas_anqp_set_element_len(buf, len); 234} 235 236 237static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd, 238 struct wpabuf *buf) 239{ 240 if (hapd->conf->ipaddr_type_configured) { 241 wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY); 242 wpabuf_put_le16(buf, 1); 243 wpabuf_put_u8(buf, hapd->conf->ipaddr_type_availability); 244 } 245} 246 247 248static void anqp_add_nai_realm_eap(struct wpabuf *buf, 249 struct hostapd_nai_realm_data *realm) 250{ 251 unsigned int i, j; 252 253 wpabuf_put_u8(buf, realm->eap_method_count); 254 255 for (i = 0; i < realm->eap_method_count; i++) { 256 struct hostapd_nai_realm_eap *eap = &realm->eap_method[i]; 257 wpabuf_put_u8(buf, 2 + (3 * eap->num_auths)); 258 wpabuf_put_u8(buf, eap->eap_method); 259 wpabuf_put_u8(buf, eap->num_auths); 260 for (j = 0; j < eap->num_auths; j++) { 261 wpabuf_put_u8(buf, eap->auth_id[j]); 262 wpabuf_put_u8(buf, 1); 263 wpabuf_put_u8(buf, eap->auth_val[j]); 264 } 265 } 266} 267 268 269static void anqp_add_nai_realm_data(struct wpabuf *buf, 270 struct hostapd_nai_realm_data *realm, 271 unsigned int realm_idx) 272{ 273 u8 *realm_data_len; 274 275 wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx], 276 (int) os_strlen(realm->realm[realm_idx])); 277 realm_data_len = wpabuf_put(buf, 2); 278 wpabuf_put_u8(buf, realm->encoding); 279 wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx])); 280 wpabuf_put_str(buf, realm->realm[realm_idx]); 281 anqp_add_nai_realm_eap(buf, realm); 282 gas_anqp_set_element_len(buf, realm_data_len); 283} 284 285 286static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd, 287 struct wpabuf *buf, 288 const u8 *home_realm, 289 size_t home_realm_len) 290{ 291 unsigned int i, j, k; 292 u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len; 293 struct hostapd_nai_realm_data *realm; 294 const u8 *pos, *realm_name, *end; 295 struct { 296 unsigned int realm_data_idx; 297 unsigned int realm_idx; 298 } matches[10]; 299 300 pos = home_realm; 301 end = pos + home_realm_len; 302 if (pos + 1 > end) { 303 wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query", 304 home_realm, home_realm_len); 305 return -1; 306 } 307 num_realms = *pos++; 308 309 for (i = 0; i < num_realms && num_matching < 10; i++) { 310 if (pos + 2 > end) { 311 wpa_hexdump(MSG_DEBUG, 312 "Truncated NAI Home Realm Query", 313 home_realm, home_realm_len); 314 return -1; 315 } 316 encoding = *pos++; 317 realm_len = *pos++; 318 if (pos + realm_len > end) { 319 wpa_hexdump(MSG_DEBUG, 320 "Truncated NAI Home Realm Query", 321 home_realm, home_realm_len); 322 return -1; 323 } 324 realm_name = pos; 325 for (j = 0; j < hapd->conf->nai_realm_count && 326 num_matching < 10; j++) { 327 const u8 *rpos, *rend; 328 realm = &hapd->conf->nai_realm_data[j]; 329 if (encoding != realm->encoding) 330 continue; 331 332 rpos = realm_name; 333 while (rpos < realm_name + realm_len && 334 num_matching < 10) { 335 for (rend = rpos; 336 rend < realm_name + realm_len; rend++) { 337 if (*rend == ';') 338 break; 339 } 340 for (k = 0; k < MAX_NAI_REALMS && 341 realm->realm[k] && 342 num_matching < 10; k++) { 343 if ((int) os_strlen(realm->realm[k]) != 344 rend - rpos || 345 os_strncmp((char *) rpos, 346 realm->realm[k], 347 rend - rpos) != 0) 348 continue; 349 matches[num_matching].realm_data_idx = 350 j; 351 matches[num_matching].realm_idx = k; 352 num_matching++; 353 } 354 rpos = rend + 1; 355 } 356 } 357 pos += realm_len; 358 } 359 360 realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM); 361 wpabuf_put_le16(buf, num_matching); 362 363 /* 364 * There are two ways to format. 1. each realm in a NAI Realm Data unit 365 * 2. all realms that share the same EAP methods in a NAI Realm Data 366 * unit. The first format is likely to be bigger in size than the 367 * second, but may be easier to parse and process by the receiver. 368 */ 369 for (i = 0; i < num_matching; i++) { 370 wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d", 371 matches[i].realm_data_idx, matches[i].realm_idx); 372 realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx]; 373 anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx); 374 } 375 gas_anqp_set_element_len(buf, realm_list_len); 376 return 0; 377} 378 379 380static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf, 381 const u8 *home_realm, size_t home_realm_len, 382 int nai_realm, int nai_home_realm) 383{ 384 if (nai_realm && hapd->conf->nai_realm_data) { 385 u8 *len; 386 unsigned int i, j; 387 len = gas_anqp_add_element(buf, ANQP_NAI_REALM); 388 wpabuf_put_le16(buf, hapd->conf->nai_realm_count); 389 for (i = 0; i < hapd->conf->nai_realm_count; i++) { 390 u8 *realm_data_len, *realm_len; 391 struct hostapd_nai_realm_data *realm; 392 393 realm = &hapd->conf->nai_realm_data[i]; 394 realm_data_len = wpabuf_put(buf, 2); 395 wpabuf_put_u8(buf, realm->encoding); 396 realm_len = wpabuf_put(buf, 1); 397 for (j = 0; realm->realm[j]; j++) { 398 if (j > 0) 399 wpabuf_put_u8(buf, ';'); 400 wpabuf_put_str(buf, realm->realm[j]); 401 } 402 *realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1; 403 anqp_add_nai_realm_eap(buf, realm); 404 gas_anqp_set_element_len(buf, realm_data_len); 405 } 406 gas_anqp_set_element_len(buf, len); 407 } else if (nai_home_realm && hapd->conf->nai_realm_data) { 408 hs20_add_nai_home_realm_matches(hapd, buf, home_realm, 409 home_realm_len); 410 } 411} 412 413 414static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd, 415 struct wpabuf *buf) 416{ 417 if (hapd->conf->anqp_3gpp_cell_net) { 418 wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK); 419 wpabuf_put_le16(buf, 420 hapd->conf->anqp_3gpp_cell_net_len); 421 wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net, 422 hapd->conf->anqp_3gpp_cell_net_len); 423 } 424} 425 426 427static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf) 428{ 429 if (hapd->conf->domain_name) { 430 wpabuf_put_le16(buf, ANQP_DOMAIN_NAME); 431 wpabuf_put_le16(buf, hapd->conf->domain_name_len); 432 wpabuf_put_data(buf, hapd->conf->domain_name, 433 hapd->conf->domain_name_len); 434 } 435} 436 437 438#ifdef CONFIG_HS20 439 440static void anqp_add_operator_friendly_name(struct hostapd_data *hapd, 441 struct wpabuf *buf) 442{ 443 if (hapd->conf->hs20_oper_friendly_name) { 444 u8 *len; 445 unsigned int i; 446 len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 447 wpabuf_put_be24(buf, OUI_WFA); 448 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 449 wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME); 450 wpabuf_put_u8(buf, 0); /* Reserved */ 451 for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++) 452 { 453 struct hostapd_lang_string *vn; 454 vn = &hapd->conf->hs20_oper_friendly_name[i]; 455 wpabuf_put_u8(buf, 3 + vn->name_len); 456 wpabuf_put_data(buf, vn->lang, 3); 457 wpabuf_put_data(buf, vn->name, vn->name_len); 458 } 459 gas_anqp_set_element_len(buf, len); 460 } 461} 462 463 464static void anqp_add_wan_metrics(struct hostapd_data *hapd, 465 struct wpabuf *buf) 466{ 467 if (hapd->conf->hs20_wan_metrics) { 468 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 469 wpabuf_put_be24(buf, OUI_WFA); 470 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 471 wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS); 472 wpabuf_put_u8(buf, 0); /* Reserved */ 473 wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13); 474 gas_anqp_set_element_len(buf, len); 475 } 476} 477 478 479static void anqp_add_connection_capability(struct hostapd_data *hapd, 480 struct wpabuf *buf) 481{ 482 if (hapd->conf->hs20_connection_capability) { 483 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 484 wpabuf_put_be24(buf, OUI_WFA); 485 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 486 wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY); 487 wpabuf_put_u8(buf, 0); /* Reserved */ 488 wpabuf_put_data(buf, hapd->conf->hs20_connection_capability, 489 hapd->conf->hs20_connection_capability_len); 490 gas_anqp_set_element_len(buf, len); 491 } 492} 493 494 495static void anqp_add_operating_class(struct hostapd_data *hapd, 496 struct wpabuf *buf) 497{ 498 if (hapd->conf->hs20_operating_class) { 499 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 500 wpabuf_put_be24(buf, OUI_WFA); 501 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 502 wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS); 503 wpabuf_put_u8(buf, 0); /* Reserved */ 504 wpabuf_put_data(buf, hapd->conf->hs20_operating_class, 505 hapd->conf->hs20_operating_class_len); 506 gas_anqp_set_element_len(buf, len); 507 } 508} 509 510#endif /* CONFIG_HS20 */ 511 512 513static struct wpabuf * 514gas_serv_build_gas_resp_payload(struct hostapd_data *hapd, 515 unsigned int request, 516 struct gas_dialog_info *di, 517 const u8 *home_realm, size_t home_realm_len) 518{ 519 struct wpabuf *buf; 520 521 buf = wpabuf_alloc(1400); 522 if (buf == NULL) 523 return NULL; 524 525 if (request & ANQP_REQ_CAPABILITY_LIST) 526 anqp_add_capab_list(hapd, buf); 527 if (request & ANQP_REQ_VENUE_NAME) 528 anqp_add_venue_name(hapd, buf); 529 if (request & ANQP_REQ_NETWORK_AUTH_TYPE) 530 anqp_add_network_auth_type(hapd, buf); 531 if (request & ANQP_REQ_ROAMING_CONSORTIUM) 532 anqp_add_roaming_consortium(hapd, buf); 533 if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY) 534 anqp_add_ip_addr_type_availability(hapd, buf); 535 if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM)) 536 anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len, 537 request & ANQP_REQ_NAI_REALM, 538 request & ANQP_REQ_NAI_HOME_REALM); 539 if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK) 540 anqp_add_3gpp_cellular_network(hapd, buf); 541 if (request & ANQP_REQ_DOMAIN_NAME) 542 anqp_add_domain_name(hapd, buf); 543 544#ifdef CONFIG_HS20 545 if (request & ANQP_REQ_HS_CAPABILITY_LIST) 546 anqp_add_hs_capab_list(hapd, buf); 547 if (request & ANQP_REQ_OPERATOR_FRIENDLY_NAME) 548 anqp_add_operator_friendly_name(hapd, buf); 549 if (request & ANQP_REQ_WAN_METRICS) 550 anqp_add_wan_metrics(hapd, buf); 551 if (request & ANQP_REQ_CONNECTION_CAPABILITY) 552 anqp_add_connection_capability(hapd, buf); 553 if (request & ANQP_REQ_OPERATING_CLASS) 554 anqp_add_operating_class(hapd, buf); 555#endif /* CONFIG_HS20 */ 556 557 return buf; 558} 559 560 561static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx) 562{ 563 struct gas_dialog_info *dia = eloop_data; 564 565 wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for " 566 "dialog token %d", dia->dialog_token); 567 568 gas_serv_dialog_clear(dia); 569} 570 571 572struct anqp_query_info { 573 unsigned int request; 574 unsigned int remote_request; 575 const u8 *home_realm_query; 576 size_t home_realm_query_len; 577 u16 remote_delay; 578}; 579 580 581static void set_anqp_req(unsigned int bit, const char *name, int local, 582 unsigned int remote, u16 remote_delay, 583 struct anqp_query_info *qi) 584{ 585 qi->request |= bit; 586 if (local) { 587 wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name); 588 } else if (bit & remote) { 589 wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name); 590 qi->remote_request |= bit; 591 if (remote_delay > qi->remote_delay) 592 qi->remote_delay = remote_delay; 593 } else { 594 wpa_printf(MSG_DEBUG, "ANQP: %s not available", name); 595 } 596} 597 598 599static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id, 600 struct anqp_query_info *qi) 601{ 602 switch (info_id) { 603 case ANQP_CAPABILITY_LIST: 604 set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0, 605 0, qi); 606 break; 607 case ANQP_VENUE_NAME: 608 set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name", 609 hapd->conf->venue_name != NULL, 0, 0, qi); 610 break; 611 case ANQP_NETWORK_AUTH_TYPE: 612 set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type", 613 hapd->conf->network_auth_type != NULL, 614 0, 0, qi); 615 break; 616 case ANQP_ROAMING_CONSORTIUM: 617 set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium", 618 hapd->conf->roaming_consortium != NULL, 0, 0, qi); 619 break; 620 case ANQP_IP_ADDR_TYPE_AVAILABILITY: 621 set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY, 622 "IP Addr Type Availability", 623 hapd->conf->ipaddr_type_configured, 624 0, 0, qi); 625 break; 626 case ANQP_NAI_REALM: 627 set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm", 628 hapd->conf->nai_realm_data != NULL, 629 0, 0, qi); 630 break; 631 case ANQP_3GPP_CELLULAR_NETWORK: 632 set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK, 633 "3GPP Cellular Network", 634 hapd->conf->anqp_3gpp_cell_net != NULL, 635 0, 0, qi); 636 break; 637 case ANQP_DOMAIN_NAME: 638 set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name", 639 hapd->conf->domain_name != NULL, 640 0, 0, qi); 641 break; 642 default: 643 wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u", 644 info_id); 645 break; 646 } 647} 648 649 650static void rx_anqp_query_list(struct hostapd_data *hapd, 651 const u8 *pos, const u8 *end, 652 struct anqp_query_info *qi) 653{ 654 wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list", 655 (unsigned int) (end - pos) / 2); 656 657 while (pos + 2 <= end) { 658 rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi); 659 pos += 2; 660 } 661} 662 663 664#ifdef CONFIG_HS20 665 666static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype, 667 struct anqp_query_info *qi) 668{ 669 switch (subtype) { 670 case HS20_STYPE_CAPABILITY_LIST: 671 set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List", 672 1, 0, 0, qi); 673 break; 674 case HS20_STYPE_OPERATOR_FRIENDLY_NAME: 675 set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME, 676 "Operator Friendly Name", 677 hapd->conf->hs20_oper_friendly_name != NULL, 678 0, 0, qi); 679 break; 680 case HS20_STYPE_WAN_METRICS: 681 set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics", 682 hapd->conf->hs20_wan_metrics != NULL, 683 0, 0, qi); 684 break; 685 case HS20_STYPE_CONNECTION_CAPABILITY: 686 set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY, 687 "Connection Capability", 688 hapd->conf->hs20_connection_capability != NULL, 689 0, 0, qi); 690 break; 691 case HS20_STYPE_OPERATING_CLASS: 692 set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class", 693 hapd->conf->hs20_operating_class != NULL, 694 0, 0, qi); 695 break; 696 default: 697 wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u", 698 subtype); 699 break; 700 } 701} 702 703 704static void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd, 705 const u8 *pos, const u8 *end, 706 struct anqp_query_info *qi) 707{ 708 qi->request |= ANQP_REQ_NAI_HOME_REALM; 709 qi->home_realm_query = pos; 710 qi->home_realm_query_len = end - pos; 711 if (hapd->conf->nai_realm_data != NULL) { 712 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query " 713 "(local)"); 714 } else { 715 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not " 716 "available"); 717 } 718} 719 720 721static void rx_anqp_vendor_specific(struct hostapd_data *hapd, 722 const u8 *pos, const u8 *end, 723 struct anqp_query_info *qi) 724{ 725 u32 oui; 726 u8 subtype; 727 728 if (pos + 4 > end) { 729 wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP " 730 "Query element"); 731 return; 732 } 733 734 oui = WPA_GET_BE24(pos); 735 pos += 3; 736 if (oui != OUI_WFA) { 737 wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x", 738 oui); 739 return; 740 } 741 742 if (*pos != HS20_ANQP_OUI_TYPE) { 743 wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u", 744 *pos); 745 return; 746 } 747 pos++; 748 749 if (pos + 1 >= end) 750 return; 751 752 subtype = *pos++; 753 pos++; /* Reserved */ 754 switch (subtype) { 755 case HS20_STYPE_QUERY_LIST: 756 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List"); 757 while (pos < end) { 758 rx_anqp_hs_query_list(hapd, *pos, qi); 759 pos++; 760 } 761 break; 762 case HS20_STYPE_NAI_HOME_REALM_QUERY: 763 rx_anqp_hs_nai_home_realm(hapd, pos, end, qi); 764 break; 765 default: 766 wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype " 767 "%u", subtype); 768 break; 769 } 770} 771 772#endif /* CONFIG_HS20 */ 773 774 775static void gas_serv_req_local_processing(struct hostapd_data *hapd, 776 const u8 *sa, u8 dialog_token, 777 struct anqp_query_info *qi) 778{ 779 struct wpabuf *buf, *tx_buf; 780 781 buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL, 782 qi->home_realm_query, 783 qi->home_realm_query_len); 784 wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses", 785 buf); 786 if (!buf) 787 return; 788 789 if (wpabuf_len(buf) > hapd->gas_frag_limit || 790 hapd->conf->gas_comeback_delay) { 791 struct gas_dialog_info *di; 792 u16 comeback_delay = 1; 793 794 if (hapd->conf->gas_comeback_delay) { 795 /* Testing - allow overriding of the delay value */ 796 comeback_delay = hapd->conf->gas_comeback_delay; 797 } 798 799 wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in " 800 "initial response - use GAS comeback"); 801 di = gas_dialog_create(hapd, sa, dialog_token); 802 if (!di) { 803 wpa_printf(MSG_INFO, "ANQP: Could not create dialog " 804 "for " MACSTR " (dialog token %u)", 805 MAC2STR(sa), dialog_token); 806 wpabuf_free(buf); 807 return; 808 } 809 di->sd_resp = buf; 810 di->sd_resp_pos = 0; 811 tx_buf = gas_anqp_build_initial_resp_buf( 812 dialog_token, WLAN_STATUS_SUCCESS, comeback_delay, 813 NULL); 814 } else { 815 wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)"); 816 tx_buf = gas_anqp_build_initial_resp_buf( 817 dialog_token, WLAN_STATUS_SUCCESS, 0, buf); 818 wpabuf_free(buf); 819 } 820 if (!tx_buf) 821 return; 822 823 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, 824 wpabuf_head(tx_buf), wpabuf_len(tx_buf)); 825 wpabuf_free(tx_buf); 826} 827 828 829static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd, 830 const u8 *sa, 831 const u8 *data, size_t len) 832{ 833 const u8 *pos = data; 834 const u8 *end = data + len; 835 const u8 *next; 836 u8 dialog_token; 837 u16 slen; 838 struct anqp_query_info qi; 839 const u8 *adv_proto; 840 841 if (len < 1 + 2) 842 return; 843 844 os_memset(&qi, 0, sizeof(qi)); 845 846 dialog_token = *pos++; 847 wpa_msg(hapd->msg_ctx, MSG_DEBUG, 848 "GAS: GAS Initial Request from " MACSTR " (dialog token %u) ", 849 MAC2STR(sa), dialog_token); 850 851 if (*pos != WLAN_EID_ADV_PROTO) { 852 wpa_msg(hapd->msg_ctx, MSG_DEBUG, 853 "GAS: Unexpected IE in GAS Initial Request: %u", *pos); 854 return; 855 } 856 adv_proto = pos++; 857 858 slen = *pos++; 859 next = pos + slen; 860 if (next > end || slen < 2) { 861 wpa_msg(hapd->msg_ctx, MSG_DEBUG, 862 "GAS: Invalid IE in GAS Initial Request"); 863 return; 864 } 865 pos++; /* skip QueryRespLenLimit and PAME-BI */ 866 867 if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { 868 struct wpabuf *buf; 869 wpa_msg(hapd->msg_ctx, MSG_DEBUG, 870 "GAS: Unsupported GAS advertisement protocol id %u", 871 *pos); 872 if (sa[0] & 0x01) 873 return; /* Invalid source address - drop silently */ 874 buf = gas_build_initial_resp( 875 dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED, 876 0, 2 + slen + 2); 877 if (buf == NULL) 878 return; 879 wpabuf_put_data(buf, adv_proto, 2 + slen); 880 wpabuf_put_le16(buf, 0); /* Query Response Length */ 881 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, 882 wpabuf_head(buf), wpabuf_len(buf)); 883 wpabuf_free(buf); 884 return; 885 } 886 887 pos = next; 888 /* Query Request */ 889 if (pos + 2 > end) 890 return; 891 slen = WPA_GET_LE16(pos); 892 pos += 2; 893 if (pos + slen > end) 894 return; 895 end = pos + slen; 896 897 /* ANQP Query Request */ 898 while (pos < end) { 899 u16 info_id, elen; 900 901 if (pos + 4 > end) 902 return; 903 904 info_id = WPA_GET_LE16(pos); 905 pos += 2; 906 elen = WPA_GET_LE16(pos); 907 pos += 2; 908 909 if (pos + elen > end) { 910 wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request"); 911 return; 912 } 913 914 switch (info_id) { 915 case ANQP_QUERY_LIST: 916 rx_anqp_query_list(hapd, pos, pos + elen, &qi); 917 break; 918#ifdef CONFIG_HS20 919 case ANQP_VENDOR_SPECIFIC: 920 rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi); 921 break; 922#endif /* CONFIG_HS20 */ 923 default: 924 wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query " 925 "Request element %u", info_id); 926 break; 927 } 928 929 pos += elen; 930 } 931 932 gas_serv_req_local_processing(hapd, sa, dialog_token, &qi); 933} 934 935 936void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst, 937 struct gas_dialog_info *dialog) 938{ 939 struct wpabuf *buf, *tx_buf; 940 u8 dialog_token = dialog->dialog_token; 941 size_t frag_len; 942 943 if (dialog->sd_resp == NULL) { 944 buf = gas_serv_build_gas_resp_payload(hapd, 945 dialog->all_requested, 946 dialog, NULL, 0); 947 wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses", 948 buf); 949 if (!buf) 950 goto tx_gas_response_done; 951 dialog->sd_resp = buf; 952 dialog->sd_resp_pos = 0; 953 } 954 frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos; 955 if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay || 956 hapd->conf->gas_comeback_delay) { 957 u16 comeback_delay_tus = dialog->comeback_delay + 958 GAS_SERV_COMEBACK_DELAY_FUDGE; 959 u32 comeback_delay_secs, comeback_delay_usecs; 960 961 if (hapd->conf->gas_comeback_delay) { 962 /* Testing - allow overriding of the delay value */ 963 comeback_delay_tus = hapd->conf->gas_comeback_delay; 964 } 965 966 wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit " 967 "%u) and comeback delay %u, " 968 "requesting comebacks", (unsigned int) frag_len, 969 (unsigned int) hapd->gas_frag_limit, 970 dialog->comeback_delay); 971 tx_buf = gas_anqp_build_initial_resp_buf(dialog_token, 972 WLAN_STATUS_SUCCESS, 973 comeback_delay_tus, 974 NULL); 975 if (tx_buf) { 976 wpa_msg(hapd->msg_ctx, MSG_DEBUG, 977 "GAS: Tx GAS Initial Resp (comeback = 10TU)"); 978 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, 979 dst, 980 wpabuf_head(tx_buf), 981 wpabuf_len(tx_buf)); 982 } 983 wpabuf_free(tx_buf); 984 985 /* start a timer of 1.5 * comeback-delay */ 986 comeback_delay_tus = comeback_delay_tus + 987 (comeback_delay_tus / 2); 988 comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000; 989 comeback_delay_usecs = (comeback_delay_tus * 1024) - 990 (comeback_delay_secs * 1000000); 991 eloop_register_timeout(comeback_delay_secs, 992 comeback_delay_usecs, 993 gas_serv_clear_cached_ies, dialog, 994 NULL); 995 goto tx_gas_response_done; 996 } 997 998 buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) + 999 dialog->sd_resp_pos, frag_len); 1000 if (buf == NULL) { 1001 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation " 1002 "failed"); 1003 goto tx_gas_response_done; 1004 } 1005 tx_buf = gas_anqp_build_initial_resp_buf(dialog_token, 1006 WLAN_STATUS_SUCCESS, 0, buf); 1007 wpabuf_free(buf); 1008 if (tx_buf == NULL) 1009 goto tx_gas_response_done; 1010 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial " 1011 "Response (frag_id %d frag_len %d)", 1012 dialog->sd_frag_id, (int) frag_len); 1013 dialog->sd_frag_id++; 1014 1015 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst, 1016 wpabuf_head(tx_buf), wpabuf_len(tx_buf)); 1017 wpabuf_free(tx_buf); 1018tx_gas_response_done: 1019 gas_serv_clear_cached_ies(dialog, NULL); 1020} 1021 1022 1023static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd, 1024 const u8 *sa, 1025 const u8 *data, size_t len) 1026{ 1027 struct gas_dialog_info *dialog; 1028 struct wpabuf *buf, *tx_buf; 1029 u8 dialog_token; 1030 size_t frag_len; 1031 int more = 0; 1032 1033 wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len); 1034 if (len < 1) 1035 return; 1036 dialog_token = *data; 1037 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u", 1038 dialog_token); 1039 1040 dialog = gas_serv_dialog_find(hapd, sa, dialog_token); 1041 if (!dialog) { 1042 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD " 1043 "response fragment for " MACSTR " dialog token %u", 1044 MAC2STR(sa), dialog_token); 1045 1046 if (sa[0] & 0x01) 1047 return; /* Invalid source address - drop silently */ 1048 tx_buf = gas_anqp_build_comeback_resp_buf( 1049 dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0, 1050 0, NULL); 1051 if (tx_buf == NULL) 1052 return; 1053 goto send_resp; 1054 } 1055 1056 if (dialog->sd_resp == NULL) { 1057 wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x", 1058 dialog->requested, dialog->received); 1059 if ((dialog->requested & dialog->received) != 1060 dialog->requested) { 1061 wpa_printf(MSG_DEBUG, "GAS: Did not receive response " 1062 "from remote processing"); 1063 gas_serv_dialog_clear(dialog); 1064 tx_buf = gas_anqp_build_comeback_resp_buf( 1065 dialog_token, 1066 WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0, 1067 NULL); 1068 if (tx_buf == NULL) 1069 return; 1070 goto send_resp; 1071 } 1072 1073 buf = gas_serv_build_gas_resp_payload(hapd, 1074 dialog->all_requested, 1075 dialog, NULL, 0); 1076 wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses", 1077 buf); 1078 if (!buf) 1079 goto rx_gas_comeback_req_done; 1080 dialog->sd_resp = buf; 1081 dialog->sd_resp_pos = 0; 1082 } 1083 frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos; 1084 if (frag_len > hapd->gas_frag_limit) { 1085 frag_len = hapd->gas_frag_limit; 1086 more = 1; 1087 } 1088 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u", 1089 (unsigned int) frag_len); 1090 buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) + 1091 dialog->sd_resp_pos, frag_len); 1092 if (buf == NULL) { 1093 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate " 1094 "buffer"); 1095 goto rx_gas_comeback_req_done; 1096 } 1097 tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token, 1098 WLAN_STATUS_SUCCESS, 1099 dialog->sd_frag_id, 1100 more, 0, buf); 1101 wpabuf_free(buf); 1102 if (tx_buf == NULL) 1103 goto rx_gas_comeback_req_done; 1104 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response " 1105 "(frag_id %d more=%d frag_len=%d)", 1106 dialog->sd_frag_id, more, (int) frag_len); 1107 dialog->sd_frag_id++; 1108 dialog->sd_resp_pos += frag_len; 1109 1110 if (more) { 1111 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain " 1112 "to be sent", 1113 (int) (wpabuf_len(dialog->sd_resp) - 1114 dialog->sd_resp_pos)); 1115 } else { 1116 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of " 1117 "SD response sent"); 1118 gas_serv_dialog_clear(dialog); 1119 gas_serv_free_dialogs(hapd, sa); 1120 } 1121 1122send_resp: 1123 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, 1124 wpabuf_head(tx_buf), wpabuf_len(tx_buf)); 1125 wpabuf_free(tx_buf); 1126 return; 1127 1128rx_gas_comeback_req_done: 1129 gas_serv_clear_cached_ies(dialog, NULL); 1130} 1131 1132 1133static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len, 1134 int freq) 1135{ 1136 struct hostapd_data *hapd = ctx; 1137 const struct ieee80211_mgmt *mgmt; 1138 size_t hdr_len; 1139 const u8 *sa, *data; 1140 1141 mgmt = (const struct ieee80211_mgmt *) buf; 1142 hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf; 1143 if (hdr_len > len) 1144 return; 1145 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC) 1146 return; 1147 sa = mgmt->sa; 1148 len -= hdr_len; 1149 data = &mgmt->u.action.u.public_action.action; 1150 switch (data[0]) { 1151 case WLAN_PA_GAS_INITIAL_REQ: 1152 gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1); 1153 break; 1154 case WLAN_PA_GAS_COMEBACK_REQ: 1155 gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1); 1156 break; 1157 } 1158} 1159 1160 1161int gas_serv_init(struct hostapd_data *hapd) 1162{ 1163 hapd->public_action_cb2 = gas_serv_rx_public_action; 1164 hapd->public_action_cb2_ctx = hapd; 1165 hapd->gas_frag_limit = 1400; 1166 if (hapd->conf->gas_frag_limit > 0) 1167 hapd->gas_frag_limit = hapd->conf->gas_frag_limit; 1168 return 0; 1169} 1170 1171 1172void gas_serv_deinit(struct hostapd_data *hapd) 1173{ 1174} 1175