1 /* 2 * Generic advertisement service (GAS) server 3 * Copyright (c) 2011-2014, Qualcomm Atheros, Inc. 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 11 #include "common.h" 12 #include "common/ieee802_11_defs.h" 13 #include "common/gas.h" 14 #include "utils/eloop.h" 15 #include "hostapd.h" 16 #include "ap_config.h" 17 #include "ap_drv_ops.h" 18 #include "sta_info.h" 19 #include "gas_serv.h" 20 21 22 static 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 29 static struct gas_dialog_info * 30 gas_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_zalloc(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 87 struct gas_dialog_info * 88 gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr, 89 u8 dialog_token) 90 { 91 struct sta_info *sta; 92 int i; 93 94 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 112 void 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 119 static 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 140 static 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 170 static 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 198 static 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 218 static 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 230 static 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 247 static 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 258 static 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 279 static 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 296 static 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 390 static 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 424 static 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 437 static 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 450 static 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 474 static 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 489 static 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 505 static 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 521 static 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 598 static 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 628 static 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 686 static struct wpabuf * 687 gas_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 745 struct 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 }; 752 753 754 static void set_anqp_req(unsigned int bit, const char *name, int local, 755 struct anqp_query_info *qi) 756 { 757 qi->request |= bit; 758 if (local) { 759 wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name); 760 } else { 761 wpa_printf(MSG_DEBUG, "ANQP: %s not available", name); 762 } 763 } 764 765 766 static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id, 767 struct anqp_query_info *qi) 768 { 769 switch (info_id) { 770 case ANQP_CAPABILITY_LIST: 771 set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 772 qi); 773 break; 774 case ANQP_VENUE_NAME: 775 set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name", 776 hapd->conf->venue_name != NULL, qi); 777 break; 778 case ANQP_NETWORK_AUTH_TYPE: 779 set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type", 780 hapd->conf->network_auth_type != NULL, qi); 781 break; 782 case ANQP_ROAMING_CONSORTIUM: 783 set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium", 784 hapd->conf->roaming_consortium != NULL, qi); 785 break; 786 case ANQP_IP_ADDR_TYPE_AVAILABILITY: 787 set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY, 788 "IP Addr Type Availability", 789 hapd->conf->ipaddr_type_configured, qi); 790 break; 791 case ANQP_NAI_REALM: 792 set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm", 793 hapd->conf->nai_realm_data != NULL, qi); 794 break; 795 case ANQP_3GPP_CELLULAR_NETWORK: 796 set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK, 797 "3GPP Cellular Network", 798 hapd->conf->anqp_3gpp_cell_net != NULL, qi); 799 break; 800 case ANQP_DOMAIN_NAME: 801 set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name", 802 hapd->conf->domain_name != NULL, qi); 803 break; 804 default: 805 wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u", 806 info_id); 807 break; 808 } 809 } 810 811 812 static void rx_anqp_query_list(struct hostapd_data *hapd, 813 const u8 *pos, const u8 *end, 814 struct anqp_query_info *qi) 815 { 816 wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list", 817 (unsigned int) (end - pos) / 2); 818 819 while (pos + 2 <= end) { 820 rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi); 821 pos += 2; 822 } 823 } 824 825 826 #ifdef CONFIG_HS20 827 828 static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype, 829 struct anqp_query_info *qi) 830 { 831 switch (subtype) { 832 case HS20_STYPE_CAPABILITY_LIST: 833 set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List", 834 1, qi); 835 break; 836 case HS20_STYPE_OPERATOR_FRIENDLY_NAME: 837 set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME, 838 "Operator Friendly Name", 839 hapd->conf->hs20_oper_friendly_name != NULL, qi); 840 break; 841 case HS20_STYPE_WAN_METRICS: 842 set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics", 843 hapd->conf->hs20_wan_metrics != NULL, qi); 844 break; 845 case HS20_STYPE_CONNECTION_CAPABILITY: 846 set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY, 847 "Connection Capability", 848 hapd->conf->hs20_connection_capability != NULL, 849 qi); 850 break; 851 case HS20_STYPE_OPERATING_CLASS: 852 set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class", 853 hapd->conf->hs20_operating_class != NULL, qi); 854 break; 855 case HS20_STYPE_OSU_PROVIDERS_LIST: 856 set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list", 857 hapd->conf->hs20_osu_providers_count, qi); 858 break; 859 default: 860 wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u", 861 subtype); 862 break; 863 } 864 } 865 866 867 static void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd, 868 const u8 *pos, const u8 *end, 869 struct anqp_query_info *qi) 870 { 871 qi->request |= ANQP_REQ_NAI_HOME_REALM; 872 qi->home_realm_query = pos; 873 qi->home_realm_query_len = end - pos; 874 if (hapd->conf->nai_realm_data != NULL) { 875 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query " 876 "(local)"); 877 } else { 878 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not " 879 "available"); 880 } 881 } 882 883 884 static void rx_anqp_hs_icon_request(struct hostapd_data *hapd, 885 const u8 *pos, const u8 *end, 886 struct anqp_query_info *qi) 887 { 888 qi->request |= ANQP_REQ_ICON_REQUEST; 889 qi->icon_name = pos; 890 qi->icon_name_len = end - pos; 891 if (hapd->conf->hs20_icons_count) { 892 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query " 893 "(local)"); 894 } else { 895 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query not " 896 "available"); 897 } 898 } 899 900 901 static void rx_anqp_vendor_specific(struct hostapd_data *hapd, 902 const u8 *pos, const u8 *end, 903 struct anqp_query_info *qi) 904 { 905 u32 oui; 906 u8 subtype; 907 908 if (pos + 4 > end) { 909 wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP " 910 "Query element"); 911 return; 912 } 913 914 oui = WPA_GET_BE24(pos); 915 pos += 3; 916 if (oui != OUI_WFA) { 917 wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x", 918 oui); 919 return; 920 } 921 922 if (*pos != HS20_ANQP_OUI_TYPE) { 923 wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u", 924 *pos); 925 return; 926 } 927 pos++; 928 929 if (pos + 1 >= end) 930 return; 931 932 subtype = *pos++; 933 pos++; /* Reserved */ 934 switch (subtype) { 935 case HS20_STYPE_QUERY_LIST: 936 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List"); 937 while (pos < end) { 938 rx_anqp_hs_query_list(hapd, *pos, qi); 939 pos++; 940 } 941 break; 942 case HS20_STYPE_NAI_HOME_REALM_QUERY: 943 rx_anqp_hs_nai_home_realm(hapd, pos, end, qi); 944 break; 945 case HS20_STYPE_ICON_REQUEST: 946 rx_anqp_hs_icon_request(hapd, pos, end, qi); 947 break; 948 default: 949 wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype " 950 "%u", subtype); 951 break; 952 } 953 } 954 955 #endif /* CONFIG_HS20 */ 956 957 958 static void gas_serv_req_local_processing(struct hostapd_data *hapd, 959 const u8 *sa, u8 dialog_token, 960 struct anqp_query_info *qi, int prot) 961 { 962 struct wpabuf *buf, *tx_buf; 963 964 buf = gas_serv_build_gas_resp_payload(hapd, qi->request, 965 qi->home_realm_query, 966 qi->home_realm_query_len, 967 qi->icon_name, qi->icon_name_len); 968 wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses", 969 buf); 970 if (!buf) 971 return; 972 973 if (wpabuf_len(buf) > hapd->gas_frag_limit || 974 hapd->conf->gas_comeback_delay) { 975 struct gas_dialog_info *di; 976 u16 comeback_delay = 1; 977 978 if (hapd->conf->gas_comeback_delay) { 979 /* Testing - allow overriding of the delay value */ 980 comeback_delay = hapd->conf->gas_comeback_delay; 981 } 982 983 wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in " 984 "initial response - use GAS comeback"); 985 di = gas_dialog_create(hapd, sa, dialog_token); 986 if (!di) { 987 wpa_printf(MSG_INFO, "ANQP: Could not create dialog " 988 "for " MACSTR " (dialog token %u)", 989 MAC2STR(sa), dialog_token); 990 wpabuf_free(buf); 991 tx_buf = gas_anqp_build_initial_resp_buf( 992 dialog_token, WLAN_STATUS_UNSPECIFIED_FAILURE, 993 0, NULL); 994 } else { 995 di->prot = prot; 996 di->sd_resp = buf; 997 di->sd_resp_pos = 0; 998 tx_buf = gas_anqp_build_initial_resp_buf( 999 dialog_token, WLAN_STATUS_SUCCESS, 1000 comeback_delay, NULL); 1001 } 1002 } else { 1003 wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)"); 1004 tx_buf = gas_anqp_build_initial_resp_buf( 1005 dialog_token, WLAN_STATUS_SUCCESS, 0, buf); 1006 wpabuf_free(buf); 1007 } 1008 if (!tx_buf) 1009 return; 1010 if (prot) 1011 convert_to_protected_dual(tx_buf); 1012 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, 1013 wpabuf_head(tx_buf), wpabuf_len(tx_buf)); 1014 wpabuf_free(tx_buf); 1015 } 1016 1017 1018 static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd, 1019 const u8 *sa, 1020 const u8 *data, size_t len, int prot) 1021 { 1022 const u8 *pos = data; 1023 const u8 *end = data + len; 1024 const u8 *next; 1025 u8 dialog_token; 1026 u16 slen; 1027 struct anqp_query_info qi; 1028 const u8 *adv_proto; 1029 1030 if (len < 1 + 2) 1031 return; 1032 1033 os_memset(&qi, 0, sizeof(qi)); 1034 1035 dialog_token = *pos++; 1036 wpa_msg(hapd->msg_ctx, MSG_DEBUG, 1037 "GAS: GAS Initial Request from " MACSTR " (dialog token %u) ", 1038 MAC2STR(sa), dialog_token); 1039 1040 if (*pos != WLAN_EID_ADV_PROTO) { 1041 wpa_msg(hapd->msg_ctx, MSG_DEBUG, 1042 "GAS: Unexpected IE in GAS Initial Request: %u", *pos); 1043 return; 1044 } 1045 adv_proto = pos++; 1046 1047 slen = *pos++; 1048 next = pos + slen; 1049 if (next > end || slen < 2) { 1050 wpa_msg(hapd->msg_ctx, MSG_DEBUG, 1051 "GAS: Invalid IE in GAS Initial Request"); 1052 return; 1053 } 1054 pos++; /* skip QueryRespLenLimit and PAME-BI */ 1055 1056 if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { 1057 struct wpabuf *buf; 1058 wpa_msg(hapd->msg_ctx, MSG_DEBUG, 1059 "GAS: Unsupported GAS advertisement protocol id %u", 1060 *pos); 1061 if (sa[0] & 0x01) 1062 return; /* Invalid source address - drop silently */ 1063 buf = gas_build_initial_resp( 1064 dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED, 1065 0, 2 + slen + 2); 1066 if (buf == NULL) 1067 return; 1068 wpabuf_put_data(buf, adv_proto, 2 + slen); 1069 wpabuf_put_le16(buf, 0); /* Query Response Length */ 1070 if (prot) 1071 convert_to_protected_dual(buf); 1072 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, 1073 wpabuf_head(buf), wpabuf_len(buf)); 1074 wpabuf_free(buf); 1075 return; 1076 } 1077 1078 pos = next; 1079 /* Query Request */ 1080 if (pos + 2 > end) 1081 return; 1082 slen = WPA_GET_LE16(pos); 1083 pos += 2; 1084 if (pos + slen > end) 1085 return; 1086 end = pos + slen; 1087 1088 /* ANQP Query Request */ 1089 while (pos < end) { 1090 u16 info_id, elen; 1091 1092 if (pos + 4 > end) 1093 return; 1094 1095 info_id = WPA_GET_LE16(pos); 1096 pos += 2; 1097 elen = WPA_GET_LE16(pos); 1098 pos += 2; 1099 1100 if (pos + elen > end) { 1101 wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request"); 1102 return; 1103 } 1104 1105 switch (info_id) { 1106 case ANQP_QUERY_LIST: 1107 rx_anqp_query_list(hapd, pos, pos + elen, &qi); 1108 break; 1109 #ifdef CONFIG_HS20 1110 case ANQP_VENDOR_SPECIFIC: 1111 rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi); 1112 break; 1113 #endif /* CONFIG_HS20 */ 1114 default: 1115 wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query " 1116 "Request element %u", info_id); 1117 break; 1118 } 1119 1120 pos += elen; 1121 } 1122 1123 gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot); 1124 } 1125 1126 1127 static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd, 1128 const u8 *sa, 1129 const u8 *data, size_t len, int prot) 1130 { 1131 struct gas_dialog_info *dialog; 1132 struct wpabuf *buf, *tx_buf; 1133 u8 dialog_token; 1134 size_t frag_len; 1135 int more = 0; 1136 1137 wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len); 1138 if (len < 1) 1139 return; 1140 dialog_token = *data; 1141 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u", 1142 dialog_token); 1143 1144 dialog = gas_serv_dialog_find(hapd, sa, dialog_token); 1145 if (!dialog) { 1146 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD " 1147 "response fragment for " MACSTR " dialog token %u", 1148 MAC2STR(sa), dialog_token); 1149 1150 if (sa[0] & 0x01) 1151 return; /* Invalid source address - drop silently */ 1152 tx_buf = gas_anqp_build_comeback_resp_buf( 1153 dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0, 1154 0, NULL); 1155 if (tx_buf == NULL) 1156 return; 1157 goto send_resp; 1158 } 1159 1160 frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos; 1161 if (frag_len > hapd->gas_frag_limit) { 1162 frag_len = hapd->gas_frag_limit; 1163 more = 1; 1164 } 1165 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u", 1166 (unsigned int) frag_len); 1167 buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) + 1168 dialog->sd_resp_pos, frag_len); 1169 if (buf == NULL) { 1170 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate " 1171 "buffer"); 1172 gas_serv_dialog_clear(dialog); 1173 return; 1174 } 1175 tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token, 1176 WLAN_STATUS_SUCCESS, 1177 dialog->sd_frag_id, 1178 more, 0, buf); 1179 wpabuf_free(buf); 1180 if (tx_buf == NULL) { 1181 gas_serv_dialog_clear(dialog); 1182 return; 1183 } 1184 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response " 1185 "(frag_id %d more=%d frag_len=%d)", 1186 dialog->sd_frag_id, more, (int) frag_len); 1187 dialog->sd_frag_id++; 1188 dialog->sd_resp_pos += frag_len; 1189 1190 if (more) { 1191 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain " 1192 "to be sent", 1193 (int) (wpabuf_len(dialog->sd_resp) - 1194 dialog->sd_resp_pos)); 1195 } else { 1196 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of " 1197 "SD response sent"); 1198 gas_serv_dialog_clear(dialog); 1199 gas_serv_free_dialogs(hapd, sa); 1200 } 1201 1202 send_resp: 1203 if (prot) 1204 convert_to_protected_dual(tx_buf); 1205 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, 1206 wpabuf_head(tx_buf), wpabuf_len(tx_buf)); 1207 wpabuf_free(tx_buf); 1208 } 1209 1210 1211 static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len, 1212 int freq) 1213 { 1214 struct hostapd_data *hapd = ctx; 1215 const struct ieee80211_mgmt *mgmt; 1216 const u8 *sa, *data; 1217 int prot; 1218 1219 mgmt = (const struct ieee80211_mgmt *) buf; 1220 if (len < IEEE80211_HDRLEN + 2) 1221 return; 1222 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC && 1223 mgmt->u.action.category != WLAN_ACTION_PROTECTED_DUAL) 1224 return; 1225 /* 1226 * Note: Public Action and Protected Dual of Public Action frames share 1227 * the same payload structure, so it is fine to use definitions of 1228 * Public Action frames to process both. 1229 */ 1230 prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL; 1231 sa = mgmt->sa; 1232 len -= IEEE80211_HDRLEN + 1; 1233 data = buf + IEEE80211_HDRLEN + 1; 1234 switch (data[0]) { 1235 case WLAN_PA_GAS_INITIAL_REQ: 1236 gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot); 1237 break; 1238 case WLAN_PA_GAS_COMEBACK_REQ: 1239 gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot); 1240 break; 1241 } 1242 } 1243 1244 1245 int gas_serv_init(struct hostapd_data *hapd) 1246 { 1247 hapd->public_action_cb2 = gas_serv_rx_public_action; 1248 hapd->public_action_cb2_ctx = hapd; 1249 hapd->gas_frag_limit = 1400; 1250 if (hapd->conf->gas_frag_limit > 0) 1251 hapd->gas_frag_limit = hapd->conf->gas_frag_limit; 1252 return 0; 1253 } 1254 1255 1256 void gas_serv_deinit(struct hostapd_data *hapd) 1257 { 1258 } 1259