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