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