1/* 2 * Generic advertisement service (GAS) query 3 * Copyright (c) 2009, Atheros Communications 4 * Copyright (c) 2011-2014, Qualcomm Atheros, Inc. 5 * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi> 6 * 7 * This software may be distributed under the terms of the BSD license. 8 * See README for more details. 9 */ 10 11#include "includes.h" 12 13#include "common.h" 14#include "utils/eloop.h" 15#include "common/ieee802_11_defs.h" 16#include "common/gas.h" 17#include "common/wpa_ctrl.h" 18#include "rsn_supp/wpa.h" 19#include "wpa_supplicant_i.h" 20#include "config.h" 21#include "driver_i.h" 22#include "offchannel.h" 23#include "gas_query.h" 24 25 26/** GAS query timeout in seconds */ 27#define GAS_QUERY_TIMEOUT_PERIOD 2 28 29/* GAS query wait-time / duration in ms */ 30#define GAS_QUERY_WAIT_TIME_INITIAL 1000 31#define GAS_QUERY_WAIT_TIME_COMEBACK 150 32 33/** 34 * struct gas_query_pending - Pending GAS query 35 */ 36struct gas_query_pending { 37 struct dl_list list; 38 struct gas_query *gas; 39 u8 addr[ETH_ALEN]; 40 u8 dialog_token; 41 u8 next_frag_id; 42 unsigned int wait_comeback:1; 43 unsigned int offchannel_tx_started:1; 44 unsigned int retry:1; 45 int freq; 46 u16 status_code; 47 struct wpabuf *req; 48 struct wpabuf *adv_proto; 49 struct wpabuf *resp; 50 struct os_reltime last_oper; 51 void (*cb)(void *ctx, const u8 *dst, u8 dialog_token, 52 enum gas_query_result result, 53 const struct wpabuf *adv_proto, 54 const struct wpabuf *resp, u16 status_code); 55 void *ctx; 56 u8 sa[ETH_ALEN]; 57}; 58 59/** 60 * struct gas_query - Internal GAS query data 61 */ 62struct gas_query { 63 struct wpa_supplicant *wpa_s; 64 struct dl_list pending; /* struct gas_query_pending */ 65 struct gas_query_pending *current; 66 struct wpa_radio_work *work; 67 struct os_reltime last_mac_addr_rand; 68 int last_rand_sa_type; 69 u8 rand_addr[ETH_ALEN]; 70}; 71 72 73static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx); 74static void gas_query_timeout(void *eloop_data, void *user_ctx); 75static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx); 76static void gas_query_tx_initial_req(struct gas_query *gas, 77 struct gas_query_pending *query); 78static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst); 79 80 81static int ms_from_time(struct os_reltime *last) 82{ 83 struct os_reltime now, res; 84 85 os_get_reltime(&now); 86 os_reltime_sub(&now, last, &res); 87 return res.sec * 1000 + res.usec / 1000; 88} 89 90 91/** 92 * gas_query_init - Initialize GAS query component 93 * @wpa_s: Pointer to wpa_supplicant data 94 * Returns: Pointer to GAS query data or %NULL on failure 95 */ 96struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s) 97{ 98 struct gas_query *gas; 99 100 gas = os_zalloc(sizeof(*gas)); 101 if (gas == NULL) 102 return NULL; 103 104 gas->wpa_s = wpa_s; 105 dl_list_init(&gas->pending); 106 107 return gas; 108} 109 110 111static const char * gas_result_txt(enum gas_query_result result) 112{ 113 switch (result) { 114 case GAS_QUERY_SUCCESS: 115 return "SUCCESS"; 116 case GAS_QUERY_FAILURE: 117 return "FAILURE"; 118 case GAS_QUERY_TIMEOUT: 119 return "TIMEOUT"; 120 case GAS_QUERY_PEER_ERROR: 121 return "PEER_ERROR"; 122 case GAS_QUERY_INTERNAL_ERROR: 123 return "INTERNAL_ERROR"; 124 case GAS_QUERY_DELETED_AT_DEINIT: 125 return "DELETED_AT_DEINIT"; 126 } 127 128 return "N/A"; 129} 130 131 132static void gas_query_free(struct gas_query_pending *query, int del_list) 133{ 134 struct gas_query *gas = query->gas; 135 136 if (del_list) 137 dl_list_del(&query->list); 138 139 if (gas->work && gas->work->ctx == query) { 140 radio_work_done(gas->work); 141 gas->work = NULL; 142 } 143 144 wpabuf_free(query->req); 145 wpabuf_free(query->adv_proto); 146 wpabuf_free(query->resp); 147 os_free(query); 148} 149 150 151static void gas_query_done(struct gas_query *gas, 152 struct gas_query_pending *query, 153 enum gas_query_result result) 154{ 155 wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_DONE "addr=" MACSTR 156 " dialog_token=%u freq=%d status_code=%u result=%s", 157 MAC2STR(query->addr), query->dialog_token, query->freq, 158 query->status_code, gas_result_txt(result)); 159 if (gas->current == query) 160 gas->current = NULL; 161 if (query->offchannel_tx_started) 162 offchannel_send_action_done(gas->wpa_s); 163 eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); 164 eloop_cancel_timeout(gas_query_timeout, gas, query); 165 eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query); 166 dl_list_del(&query->list); 167 query->cb(query->ctx, query->addr, query->dialog_token, result, 168 query->adv_proto, query->resp, query->status_code); 169 gas_query_free(query, 0); 170} 171 172 173/** 174 * gas_query_deinit - Deinitialize GAS query component 175 * @gas: GAS query data from gas_query_init() 176 */ 177void gas_query_deinit(struct gas_query *gas) 178{ 179 struct gas_query_pending *query, *next; 180 181 if (gas == NULL) 182 return; 183 184 dl_list_for_each_safe(query, next, &gas->pending, 185 struct gas_query_pending, list) 186 gas_query_done(gas, query, GAS_QUERY_DELETED_AT_DEINIT); 187 188 os_free(gas); 189} 190 191 192static struct gas_query_pending * 193gas_query_get_pending(struct gas_query *gas, const u8 *addr, u8 dialog_token) 194{ 195 struct gas_query_pending *q; 196 dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { 197 if (os_memcmp(q->addr, addr, ETH_ALEN) == 0 && 198 q->dialog_token == dialog_token) 199 return q; 200 } 201 return NULL; 202} 203 204 205static int gas_query_append(struct gas_query_pending *query, const u8 *data, 206 size_t len) 207{ 208 if (wpabuf_resize(&query->resp, len) < 0) { 209 wpa_printf(MSG_DEBUG, "GAS: No memory to store the response"); 210 return -1; 211 } 212 wpabuf_put_data(query->resp, data, len); 213 return 0; 214} 215 216 217static void gas_query_tx_status(struct wpa_supplicant *wpa_s, 218 unsigned int freq, const u8 *dst, 219 const u8 *src, const u8 *bssid, 220 const u8 *data, size_t data_len, 221 enum offchannel_send_action_result result) 222{ 223 struct gas_query_pending *query; 224 struct gas_query *gas = wpa_s->gas; 225 int dur; 226 227 if (gas->current == NULL) { 228 wpa_printf(MSG_DEBUG, "GAS: Unexpected TX status: freq=%u dst=" 229 MACSTR " result=%d - no query in progress", 230 freq, MAC2STR(dst), result); 231 return; 232 } 233 234 query = gas->current; 235 236 dur = ms_from_time(&query->last_oper); 237 wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR 238 " result=%d query=%p dialog_token=%u dur=%d ms", 239 freq, MAC2STR(dst), result, query, query->dialog_token, dur); 240 if (os_memcmp(dst, query->addr, ETH_ALEN) != 0) { 241 wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination"); 242 return; 243 } 244 os_get_reltime(&query->last_oper); 245 246 if (result == OFFCHANNEL_SEND_ACTION_SUCCESS || 247 result == OFFCHANNEL_SEND_ACTION_NO_ACK) { 248 eloop_cancel_timeout(gas_query_timeout, gas, query); 249 if (result == OFFCHANNEL_SEND_ACTION_NO_ACK) { 250 wpa_printf(MSG_DEBUG, "GAS: No ACK to GAS request"); 251 eloop_register_timeout(0, 250000, 252 gas_query_timeout, gas, query); 253 } else { 254 eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, 255 gas_query_timeout, gas, query); 256 } 257 if (query->wait_comeback && !query->retry) { 258 eloop_cancel_timeout(gas_query_rx_comeback_timeout, 259 gas, query); 260 eloop_register_timeout( 261 0, (GAS_QUERY_WAIT_TIME_COMEBACK + 10) * 1000, 262 gas_query_rx_comeback_timeout, gas, query); 263 } 264 } 265 if (result == OFFCHANNEL_SEND_ACTION_FAILED) { 266 eloop_cancel_timeout(gas_query_timeout, gas, query); 267 eloop_register_timeout(0, 0, gas_query_timeout, gas, query); 268 } 269} 270 271 272static int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr) 273{ 274 if (wpa_s->current_ssid == NULL || 275 wpa_s->wpa_state < WPA_4WAY_HANDSHAKE || 276 os_memcmp(addr, wpa_s->bssid, ETH_ALEN) != 0) 277 return 0; 278 return wpa_sm_pmf_enabled(wpa_s->wpa); 279} 280 281 282static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, 283 struct wpabuf *req, unsigned int wait_time) 284{ 285 int res, prot = pmf_in_use(gas->wpa_s, query->addr); 286 const u8 *bssid; 287 const u8 wildcard_bssid[ETH_ALEN] = { 288 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 289 }; 290 291 wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u " 292 "freq=%d prot=%d using src addr " MACSTR, 293 MAC2STR(query->addr), (unsigned int) wpabuf_len(req), 294 query->freq, prot, MAC2STR(query->sa)); 295 if (prot) { 296 u8 *categ = wpabuf_mhead_u8(req); 297 *categ = WLAN_ACTION_PROTECTED_DUAL; 298 } 299 os_get_reltime(&query->last_oper); 300 if (gas->wpa_s->max_remain_on_chan && 301 wait_time > gas->wpa_s->max_remain_on_chan) 302 wait_time = gas->wpa_s->max_remain_on_chan; 303 if (!gas->wpa_s->conf->gas_address3 || 304 (gas->wpa_s->current_ssid && 305 gas->wpa_s->wpa_state >= WPA_ASSOCIATED && 306 os_memcmp(query->addr, gas->wpa_s->bssid, ETH_ALEN) == 0)) 307 bssid = query->addr; 308 else 309 bssid = wildcard_bssid; 310 311 res = offchannel_send_action(gas->wpa_s, query->freq, query->addr, 312 query->sa, bssid, wpabuf_head(req), 313 wpabuf_len(req), wait_time, 314 gas_query_tx_status, 0); 315 316 if (res == 0) 317 query->offchannel_tx_started = 1; 318 return res; 319} 320 321 322static void gas_query_tx_comeback_req(struct gas_query *gas, 323 struct gas_query_pending *query) 324{ 325 struct wpabuf *req; 326 unsigned int wait_time; 327 328 req = gas_build_comeback_req(query->dialog_token); 329 if (req == NULL) { 330 gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 331 return; 332 } 333 334 wait_time = (query->retry || !query->offchannel_tx_started) ? 335 GAS_QUERY_WAIT_TIME_INITIAL : GAS_QUERY_WAIT_TIME_COMEBACK; 336 337 if (gas_query_tx(gas, query, req, wait_time) < 0) { 338 wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " 339 MACSTR, MAC2STR(query->addr)); 340 gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 341 } 342 343 wpabuf_free(req); 344} 345 346 347static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx) 348{ 349 struct gas_query *gas = eloop_data; 350 struct gas_query_pending *query = user_ctx; 351 int dialog_token; 352 353 wpa_printf(MSG_DEBUG, 354 "GAS: No response to comeback request received (retry=%u)", 355 query->retry); 356 if (gas->current != query || query->retry) 357 return; 358 dialog_token = gas_query_new_dialog_token(gas, query->addr); 359 if (dialog_token < 0) 360 return; 361 wpa_printf(MSG_DEBUG, 362 "GAS: Retry GAS query due to comeback response timeout"); 363 query->retry = 1; 364 query->dialog_token = dialog_token; 365 *(wpabuf_mhead_u8(query->req) + 2) = dialog_token; 366 query->wait_comeback = 0; 367 query->next_frag_id = 0; 368 wpabuf_free(query->adv_proto); 369 query->adv_proto = NULL; 370 eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); 371 eloop_cancel_timeout(gas_query_timeout, gas, query); 372 gas_query_tx_initial_req(gas, query); 373} 374 375 376static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx) 377{ 378 struct gas_query *gas = eloop_data; 379 struct gas_query_pending *query = user_ctx; 380 381 wpa_printf(MSG_DEBUG, "GAS: Comeback timeout for request to " MACSTR, 382 MAC2STR(query->addr)); 383 gas_query_tx_comeback_req(gas, query); 384} 385 386 387static void gas_query_tx_comeback_req_delay(struct gas_query *gas, 388 struct gas_query_pending *query, 389 u16 comeback_delay) 390{ 391 unsigned int secs, usecs; 392 393 if (comeback_delay > 1 && query->offchannel_tx_started) { 394 offchannel_send_action_done(gas->wpa_s); 395 query->offchannel_tx_started = 0; 396 } 397 398 secs = (comeback_delay * 1024) / 1000000; 399 usecs = comeback_delay * 1024 - secs * 1000000; 400 wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR 401 " in %u secs %u usecs", MAC2STR(query->addr), secs, usecs); 402 eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); 403 eloop_register_timeout(secs, usecs, gas_query_tx_comeback_timeout, 404 gas, query); 405} 406 407 408static void gas_query_rx_initial(struct gas_query *gas, 409 struct gas_query_pending *query, 410 const u8 *adv_proto, const u8 *resp, 411 size_t len, u16 comeback_delay) 412{ 413 wpa_printf(MSG_DEBUG, "GAS: Received initial response from " 414 MACSTR " (dialog_token=%u comeback_delay=%u)", 415 MAC2STR(query->addr), query->dialog_token, comeback_delay); 416 417 query->adv_proto = wpabuf_alloc_copy(adv_proto, 2 + adv_proto[1]); 418 if (query->adv_proto == NULL) { 419 gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 420 return; 421 } 422 423 if (comeback_delay) { 424 eloop_cancel_timeout(gas_query_timeout, gas, query); 425 query->wait_comeback = 1; 426 gas_query_tx_comeback_req_delay(gas, query, comeback_delay); 427 return; 428 } 429 430 /* Query was completed without comeback mechanism */ 431 if (gas_query_append(query, resp, len) < 0) { 432 gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 433 return; 434 } 435 436 gas_query_done(gas, query, GAS_QUERY_SUCCESS); 437} 438 439 440static void gas_query_rx_comeback(struct gas_query *gas, 441 struct gas_query_pending *query, 442 const u8 *adv_proto, const u8 *resp, 443 size_t len, u8 frag_id, u8 more_frags, 444 u16 comeback_delay) 445{ 446 wpa_printf(MSG_DEBUG, "GAS: Received comeback response from " 447 MACSTR " (dialog_token=%u frag_id=%u more_frags=%u " 448 "comeback_delay=%u)", 449 MAC2STR(query->addr), query->dialog_token, frag_id, 450 more_frags, comeback_delay); 451 eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query); 452 453 if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) || 454 os_memcmp(adv_proto, wpabuf_head(query->adv_proto), 455 wpabuf_len(query->adv_proto)) != 0) { 456 wpa_printf(MSG_DEBUG, "GAS: Advertisement Protocol changed " 457 "between initial and comeback response from " 458 MACSTR, MAC2STR(query->addr)); 459 gas_query_done(gas, query, GAS_QUERY_PEER_ERROR); 460 return; 461 } 462 463 if (comeback_delay) { 464 if (frag_id) { 465 wpa_printf(MSG_DEBUG, "GAS: Invalid comeback response " 466 "with non-zero frag_id and comeback_delay " 467 "from " MACSTR, MAC2STR(query->addr)); 468 gas_query_done(gas, query, GAS_QUERY_PEER_ERROR); 469 return; 470 } 471 gas_query_tx_comeback_req_delay(gas, query, comeback_delay); 472 return; 473 } 474 475 if (frag_id != query->next_frag_id) { 476 wpa_printf(MSG_DEBUG, "GAS: Unexpected frag_id in response " 477 "from " MACSTR, MAC2STR(query->addr)); 478 if (frag_id + 1 == query->next_frag_id) { 479 wpa_printf(MSG_DEBUG, "GAS: Drop frame as possible " 480 "retry of previous fragment"); 481 return; 482 } 483 gas_query_done(gas, query, GAS_QUERY_PEER_ERROR); 484 return; 485 } 486 query->next_frag_id++; 487 488 if (gas_query_append(query, resp, len) < 0) { 489 gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 490 return; 491 } 492 493 if (more_frags) { 494 gas_query_tx_comeback_req(gas, query); 495 return; 496 } 497 498 gas_query_done(gas, query, GAS_QUERY_SUCCESS); 499} 500 501 502/** 503 * gas_query_rx - Indicate reception of a Public Action or Protected Dual frame 504 * @gas: GAS query data from gas_query_init() 505 * @da: Destination MAC address of the Action frame 506 * @sa: Source MAC address of the Action frame 507 * @bssid: BSSID of the Action frame 508 * @categ: Category of the Action frame 509 * @data: Payload of the Action frame 510 * @len: Length of @data 511 * @freq: Frequency (in MHz) on which the frame was received 512 * Returns: 0 if the Public Action frame was a GAS frame or -1 if not 513 */ 514int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, 515 const u8 *bssid, u8 categ, const u8 *data, size_t len, 516 int freq) 517{ 518 struct gas_query_pending *query; 519 u8 action, dialog_token, frag_id = 0, more_frags = 0; 520 u16 comeback_delay, resp_len; 521 const u8 *pos, *adv_proto; 522 int prot, pmf; 523 unsigned int left; 524 525 if (gas == NULL || len < 4) 526 return -1; 527 528 pos = data; 529 action = *pos++; 530 dialog_token = *pos++; 531 532 if (action != WLAN_PA_GAS_INITIAL_RESP && 533 action != WLAN_PA_GAS_COMEBACK_RESP) 534 return -1; /* Not a GAS response */ 535 536 prot = categ == WLAN_ACTION_PROTECTED_DUAL; 537 pmf = pmf_in_use(gas->wpa_s, sa); 538 if (prot && !pmf) { 539 wpa_printf(MSG_DEBUG, "GAS: Drop unexpected protected GAS frame when PMF is disabled"); 540 return 0; 541 } 542 if (!prot && pmf) { 543 wpa_printf(MSG_DEBUG, "GAS: Drop unexpected unprotected GAS frame when PMF is enabled"); 544 return 0; 545 } 546 547 query = gas_query_get_pending(gas, sa, dialog_token); 548 if (query == NULL) { 549 wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR 550 " dialog token %u", MAC2STR(sa), dialog_token); 551 return -1; 552 } 553 554 wpa_printf(MSG_DEBUG, "GAS: Response in %d ms from " MACSTR, 555 ms_from_time(&query->last_oper), MAC2STR(sa)); 556 557 if (query->wait_comeback && action == WLAN_PA_GAS_INITIAL_RESP) { 558 wpa_printf(MSG_DEBUG, "GAS: Unexpected initial response from " 559 MACSTR " dialog token %u when waiting for comeback " 560 "response", MAC2STR(sa), dialog_token); 561 return 0; 562 } 563 564 if (!query->wait_comeback && action == WLAN_PA_GAS_COMEBACK_RESP) { 565 wpa_printf(MSG_DEBUG, "GAS: Unexpected comeback response from " 566 MACSTR " dialog token %u when waiting for initial " 567 "response", MAC2STR(sa), dialog_token); 568 return 0; 569 } 570 571 query->status_code = WPA_GET_LE16(pos); 572 pos += 2; 573 574 if (query->status_code == WLAN_STATUS_QUERY_RESP_OUTSTANDING && 575 action == WLAN_PA_GAS_COMEBACK_RESP) { 576 wpa_printf(MSG_DEBUG, "GAS: Allow non-zero status for outstanding comeback response"); 577 } else if (query->status_code != WLAN_STATUS_SUCCESS) { 578 wpa_printf(MSG_DEBUG, "GAS: Query to " MACSTR " dialog token " 579 "%u failed - status code %u", 580 MAC2STR(sa), dialog_token, query->status_code); 581 gas_query_done(gas, query, GAS_QUERY_FAILURE); 582 return 0; 583 } 584 585 if (action == WLAN_PA_GAS_COMEBACK_RESP) { 586 if (pos + 1 > data + len) 587 return 0; 588 frag_id = *pos & 0x7f; 589 more_frags = (*pos & 0x80) >> 7; 590 pos++; 591 } 592 593 /* Comeback Delay */ 594 if (pos + 2 > data + len) 595 return 0; 596 comeback_delay = WPA_GET_LE16(pos); 597 pos += 2; 598 599 /* Advertisement Protocol element */ 600 if (pos + 2 > data + len || pos + 2 + pos[1] > data + len) { 601 wpa_printf(MSG_DEBUG, "GAS: No room for Advertisement " 602 "Protocol element in the response from " MACSTR, 603 MAC2STR(sa)); 604 return 0; 605 } 606 607 if (*pos != WLAN_EID_ADV_PROTO) { 608 wpa_printf(MSG_DEBUG, "GAS: Unexpected Advertisement " 609 "Protocol element ID %u in response from " MACSTR, 610 *pos, MAC2STR(sa)); 611 return 0; 612 } 613 614 adv_proto = pos; 615 pos += 2 + pos[1]; 616 617 /* Query Response Length */ 618 if (pos + 2 > data + len) { 619 wpa_printf(MSG_DEBUG, "GAS: No room for GAS Response Length"); 620 return 0; 621 } 622 resp_len = WPA_GET_LE16(pos); 623 pos += 2; 624 625 left = data + len - pos; 626 if (resp_len > left) { 627 wpa_printf(MSG_DEBUG, "GAS: Truncated Query Response in " 628 "response from " MACSTR, MAC2STR(sa)); 629 return 0; 630 } 631 632 if (resp_len < left) { 633 wpa_printf(MSG_DEBUG, "GAS: Ignore %u octets of extra data " 634 "after Query Response from " MACSTR, 635 left - resp_len, MAC2STR(sa)); 636 } 637 638 if (action == WLAN_PA_GAS_COMEBACK_RESP) 639 gas_query_rx_comeback(gas, query, adv_proto, pos, resp_len, 640 frag_id, more_frags, comeback_delay); 641 else 642 gas_query_rx_initial(gas, query, adv_proto, pos, resp_len, 643 comeback_delay); 644 645 return 0; 646} 647 648 649static void gas_query_timeout(void *eloop_data, void *user_ctx) 650{ 651 struct gas_query *gas = eloop_data; 652 struct gas_query_pending *query = user_ctx; 653 654 wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR 655 " dialog token %u", 656 MAC2STR(query->addr), query->dialog_token); 657 gas_query_done(gas, query, GAS_QUERY_TIMEOUT); 658} 659 660 661static int gas_query_dialog_token_available(struct gas_query *gas, 662 const u8 *dst, u8 dialog_token) 663{ 664 struct gas_query_pending *q; 665 dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { 666 if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 && 667 dialog_token == q->dialog_token) 668 return 0; 669 } 670 671 return 1; 672} 673 674 675static void gas_query_start_cb(struct wpa_radio_work *work, int deinit) 676{ 677 struct gas_query_pending *query = work->ctx; 678 struct gas_query *gas = query->gas; 679 struct wpa_supplicant *wpa_s = gas->wpa_s; 680 681 if (deinit) { 682 if (work->started) { 683 gas->work = NULL; 684 gas_query_done(gas, query, GAS_QUERY_DELETED_AT_DEINIT); 685 return; 686 } 687 688 gas_query_free(query, 1); 689 return; 690 } 691 692 if (wpas_update_random_addr_disassoc(wpa_s) < 0) { 693 wpa_msg(wpa_s, MSG_INFO, 694 "Failed to assign random MAC address for GAS"); 695 gas_query_free(query, 1); 696 radio_work_done(work); 697 return; 698 } 699 700 gas->work = work; 701 gas_query_tx_initial_req(gas, query); 702} 703 704 705static void gas_query_tx_initial_req(struct gas_query *gas, 706 struct gas_query_pending *query) 707{ 708 if (gas_query_tx(gas, query, query->req, 709 GAS_QUERY_WAIT_TIME_INITIAL) < 0) { 710 wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " 711 MACSTR, MAC2STR(query->addr)); 712 gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 713 return; 714 } 715 gas->current = query; 716 717 wpa_printf(MSG_DEBUG, "GAS: Starting query timeout for dialog token %u", 718 query->dialog_token); 719 eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, 720 gas_query_timeout, gas, query); 721} 722 723 724static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst) 725{ 726 static int next_start = 0; 727 int dialog_token; 728 729 for (dialog_token = 0; dialog_token < 256; dialog_token++) { 730 if (gas_query_dialog_token_available( 731 gas, dst, (next_start + dialog_token) % 256)) 732 break; 733 } 734 if (dialog_token == 256) 735 return -1; /* Too many pending queries */ 736 dialog_token = (next_start + dialog_token) % 256; 737 next_start = (dialog_token + 1) % 256; 738 return dialog_token; 739} 740 741 742static int gas_query_set_sa(struct gas_query *gas, 743 struct gas_query_pending *query) 744{ 745 struct wpa_supplicant *wpa_s = gas->wpa_s; 746 struct os_reltime now; 747 748 if (!wpa_s->conf->gas_rand_mac_addr || 749 !(wpa_s->current_bss ? 750 (wpa_s->drv_flags & 751 WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED) : 752 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA))) { 753 /* Use own MAC address as the transmitter address */ 754 os_memcpy(query->sa, wpa_s->own_addr, ETH_ALEN); 755 return 0; 756 } 757 758 os_get_reltime(&now); 759 760 if (wpa_s->conf->gas_rand_mac_addr == gas->last_rand_sa_type && 761 gas->last_mac_addr_rand.sec != 0 && 762 !os_reltime_expired(&now, &gas->last_mac_addr_rand, 763 wpa_s->conf->gas_rand_addr_lifetime)) { 764 wpa_printf(MSG_DEBUG, 765 "GAS: Use the previously selected random transmitter address " 766 MACSTR, MAC2STR(gas->rand_addr)); 767 os_memcpy(query->sa, gas->rand_addr, ETH_ALEN); 768 return 0; 769 } 770 771 if (wpa_s->conf->gas_rand_mac_addr == 1 && 772 random_mac_addr(gas->rand_addr) < 0) { 773 wpa_printf(MSG_ERROR, "GAS: Failed to get random address"); 774 return -1; 775 } 776 777 if (wpa_s->conf->gas_rand_mac_addr == 2 && 778 random_mac_addr_keep_oui(gas->rand_addr) < 0) { 779 wpa_printf(MSG_ERROR, 780 "GAS: Failed to get random address with same OUI"); 781 return -1; 782 } 783 784 wpa_printf(MSG_DEBUG, "GAS: Use a new random transmitter address " 785 MACSTR, MAC2STR(gas->rand_addr)); 786 os_memcpy(query->sa, gas->rand_addr, ETH_ALEN); 787 os_get_reltime(&gas->last_mac_addr_rand); 788 gas->last_rand_sa_type = wpa_s->conf->gas_rand_mac_addr; 789 790 return 0; 791} 792 793 794/** 795 * gas_query_req - Request a GAS query 796 * @gas: GAS query data from gas_query_init() 797 * @dst: Destination MAC address for the query 798 * @freq: Frequency (in MHz) for the channel on which to send the query 799 * @req: GAS query payload (to be freed by gas_query module in case of success 800 * return) 801 * @cb: Callback function for reporting GAS query result and response 802 * @ctx: Context pointer to use with the @cb call 803 * Returns: dialog token (>= 0) on success or -1 on failure 804 */ 805int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, 806 struct wpabuf *req, 807 void (*cb)(void *ctx, const u8 *dst, u8 dialog_token, 808 enum gas_query_result result, 809 const struct wpabuf *adv_proto, 810 const struct wpabuf *resp, u16 status_code), 811 void *ctx) 812{ 813 struct gas_query_pending *query; 814 int dialog_token; 815 816 if (wpabuf_len(req) < 3) 817 return -1; 818 819 dialog_token = gas_query_new_dialog_token(gas, dst); 820 if (dialog_token < 0) 821 return -1; 822 823 query = os_zalloc(sizeof(*query)); 824 if (query == NULL) 825 return -1; 826 827 query->gas = gas; 828 if (gas_query_set_sa(gas, query)) { 829 os_free(query); 830 return -1; 831 } 832 os_memcpy(query->addr, dst, ETH_ALEN); 833 query->dialog_token = dialog_token; 834 query->freq = freq; 835 query->cb = cb; 836 query->ctx = ctx; 837 query->req = req; 838 dl_list_add(&gas->pending, &query->list); 839 840 *(wpabuf_mhead_u8(req) + 2) = dialog_token; 841 842 wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_START "addr=" MACSTR 843 " dialog_token=%u freq=%d", 844 MAC2STR(query->addr), query->dialog_token, query->freq); 845 846 if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb, 847 query) < 0) { 848 query->req = NULL; /* caller will free this in error case */ 849 gas_query_free(query, 1); 850 return -1; 851 } 852 853 return dialog_token; 854} 855