11f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/* 21f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Generic advertisement service (GAS) query 31f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Copyright (c) 2009, Atheros Communications 41f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Copyright (c) 2011, Qualcomm Atheros 51f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 7c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 81f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */ 91f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "includes.h" 111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "common.h" 131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "utils/eloop.h" 141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "common/ieee802_11_defs.h" 151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "common/gas.h" 161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "wpa_supplicant_i.h" 171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "driver_i.h" 181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "offchannel.h" 191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "gas_query.h" 201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#define GAS_QUERY_TIMEOUT 5 231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct gas_query_pending { 261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct dl_list list; 271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 addr[ETH_ALEN]; 281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 dialog_token; 291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 next_frag_id; 301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt unsigned int wait_comeback:1; 311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt unsigned int offchannel_tx_started:1; 321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt int freq; 331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u16 status_code; 341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct wpabuf *adv_proto; 351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct wpabuf *resp; 361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt void (*cb)(void *ctx, const u8 *dst, u8 dialog_token, 371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt enum gas_query_result result, 381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const struct wpabuf *adv_proto, 391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const struct wpabuf *resp, u16 status_code); 401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt void *ctx; 411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}; 421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct gas_query { 441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct wpa_supplicant *wpa_s; 451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct dl_list pending; /* struct gas_query_pending */ 461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}; 471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx); 501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_timeout(void *eloop_data, void *user_ctx); 511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct gas_query * gas_query_init(struct wpa_supplicant *wpa_s) 541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query *gas; 561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas = os_zalloc(sizeof(*gas)); 581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (gas == NULL) 591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return NULL; 601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas->wpa_s = wpa_s; 621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dl_list_init(&gas->pending); 631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return gas; 651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_done(struct gas_query *gas, 691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query, 701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt enum gas_query_result result) 711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (query->offchannel_tx_started) 731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt offchannel_send_action_done(gas->wpa_s); 741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); 751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt eloop_cancel_timeout(gas_query_timeout, gas, query); 761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dl_list_del(&query->list); 771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->cb(query->ctx, query->addr, query->dialog_token, result, 781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->adv_proto, query->resp, query->status_code); 791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpabuf_free(query->adv_proto); 801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpabuf_free(query->resp); 811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(query); 821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtvoid gas_query_deinit(struct gas_query *gas) 861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query, *next; 881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (gas == NULL) 901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dl_list_for_each_safe(query, next, &gas->pending, 931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending, list) 941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_DELETED_AT_DEINIT); 951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(gas); 971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic struct gas_query_pending * 1011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtgas_query_get_pending(struct gas_query *gas, const u8 *addr, u8 dialog_token) 1021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 1031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *q; 1041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { 1051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (os_memcmp(q->addr, addr, ETH_ALEN) == 0 && 1061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt q->dialog_token == dialog_token) 1071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return q; 1081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 1091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return NULL; 1101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 1111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int gas_query_append(struct gas_query_pending *query, const u8 *data, 1141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t len) 1151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 1161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (wpabuf_resize(&query->resp, len) < 0) { 1171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: No memory to store the response"); 1181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return -1; 1191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 1201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpabuf_put_data(query->resp, data, len); 1211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 1221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 1231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, 1261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct wpabuf *req) 1271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 1281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt int res; 1291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u " 1301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "freq=%d", MAC2STR(query->addr), 1311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt (unsigned int) wpabuf_len(req), query->freq); 1321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt res = offchannel_send_action(gas->wpa_s, query->freq, query->addr, 1331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas->wpa_s->own_addr, query->addr, 1341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpabuf_head(req), wpabuf_len(req), 1000, 1351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt NULL, 0); 1361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (res == 0) 1371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->offchannel_tx_started = 1; 1381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return res; 1391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 1401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_tx_comeback_req(struct gas_query *gas, 1431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query) 1441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 1451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct wpabuf *req; 1461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt req = gas_build_comeback_req(query->dialog_token); 1481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (req == NULL) { 1491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 1501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 1511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 1521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (gas_query_tx(gas, query, req) < 0) { 1541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " 1551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MACSTR, MAC2STR(query->addr)); 1561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 1571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 1581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpabuf_free(req); 1601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 1611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx) 1641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 1651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query *gas = eloop_data; 1661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query = user_ctx; 1671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Comeback timeout for request to " MACSTR, 1691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MAC2STR(query->addr)); 1701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_tx_comeback_req(gas, query); 1711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 1721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_tx_comeback_req_delay(struct gas_query *gas, 1751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query, 1761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u16 comeback_delay) 1771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 1781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt unsigned int secs, usecs; 1791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt secs = (comeback_delay * 1024) / 1000000; 1811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt usecs = comeback_delay * 1024 - secs * 1000000; 1821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR 1831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt " in %u secs %u usecs", MAC2STR(query->addr), secs, usecs); 1841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); 1851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt eloop_register_timeout(secs, usecs, gas_query_tx_comeback_timeout, 1861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas, query); 1871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 1881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_rx_initial(struct gas_query *gas, 1911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query, 1921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *adv_proto, const u8 *resp, 1931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t len, u16 comeback_delay) 1941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 1951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Received initial response from " 1961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MACSTR " (dialog_token=%u comeback_delay=%u)", 1971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MAC2STR(query->addr), query->dialog_token, comeback_delay); 1981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->adv_proto = wpabuf_alloc_copy(adv_proto, 2 + adv_proto[1]); 2001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (query->adv_proto == NULL) { 2011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 2021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 2031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 2041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (comeback_delay) { 2061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->wait_comeback = 1; 2071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_tx_comeback_req_delay(gas, query, comeback_delay); 2081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 2091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 2101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* Query was completed without comeback mechanism */ 2121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (gas_query_append(query, resp, len) < 0) { 2131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 2141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 2151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 2161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_SUCCESS); 2181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 2191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_rx_comeback(struct gas_query *gas, 2221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query, 2231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *adv_proto, const u8 *resp, 2241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t len, u8 frag_id, u8 more_frags, 2251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u16 comeback_delay) 2261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 2271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Received comeback response from " 2281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MACSTR " (dialog_token=%u frag_id=%u more_frags=%u " 2291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "comeback_delay=%u)", 2301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MAC2STR(query->addr), query->dialog_token, frag_id, 2311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt more_frags, comeback_delay); 2321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) || 2341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcmp(adv_proto, wpabuf_head(query->adv_proto), 2351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpabuf_len(query->adv_proto)) != 0) { 2361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Advertisement Protocol changed " 2371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "between initial and comeback response from " 2381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MACSTR, MAC2STR(query->addr)); 2391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_PEER_ERROR); 2401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 2411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 2421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (comeback_delay) { 2441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (frag_id) { 2451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Invalid comeback response " 2461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "with non-zero frag_id and comeback_delay " 2471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "from " MACSTR, MAC2STR(query->addr)); 2481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_PEER_ERROR); 2491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 2501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 2511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_tx_comeback_req_delay(gas, query, comeback_delay); 2521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 2531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 2541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (frag_id != query->next_frag_id) { 2561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Unexpected frag_id in response " 2571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "from " MACSTR, MAC2STR(query->addr)); 2581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_PEER_ERROR); 2591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 2601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 2611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->next_frag_id++; 2621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (gas_query_append(query, resp, len) < 0) { 2641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 2651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 2661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 2671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (more_frags) { 2691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_tx_comeback_req(gas, query); 2701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 2711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 2721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_SUCCESS); 2741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 2751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, 2781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *bssid, const u8 *data, size_t len, int freq) 2791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 2801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query; 2811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 action, dialog_token, frag_id = 0, more_frags = 0; 2821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u16 comeback_delay, resp_len; 2831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *pos, *adv_proto; 2841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (gas == NULL || len < 4) 2861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return -1; 2871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos = data; 2891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt action = *pos++; 2901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dialog_token = *pos++; 2911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (action != WLAN_PA_GAS_INITIAL_RESP && 2931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt action != WLAN_PA_GAS_COMEBACK_RESP) 2941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return -1; /* Not a GAS response */ 2951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query = gas_query_get_pending(gas, sa, dialog_token); 2971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (query == NULL) { 2981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR 2991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt " dialog token %u", MAC2STR(sa), dialog_token); 3001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return -1; 3011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (query->wait_comeback && action == WLAN_PA_GAS_INITIAL_RESP) { 3041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Unexpected initial response from " 3051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MACSTR " dialog token %u when waiting for comeback " 3061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "response", MAC2STR(sa), dialog_token); 3071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 3081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (!query->wait_comeback && action == WLAN_PA_GAS_COMEBACK_RESP) { 3111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Unexpected comeback response from " 3121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MACSTR " dialog token %u when waiting for initial " 3131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "response", MAC2STR(sa), dialog_token); 3141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 3151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->status_code = WPA_GET_LE16(pos); 3181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos += 2; 3191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (query->status_code != WLAN_STATUS_SUCCESS) { 3211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Query to " MACSTR " dialog token " 3221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "%u failed - status code %u", 3231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MAC2STR(sa), dialog_token, query->status_code); 3241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_FAILURE); 3251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 3261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (action == WLAN_PA_GAS_COMEBACK_RESP) { 3291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (pos + 1 > data + len) 3301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 3311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt frag_id = *pos & 0x7f; 3321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt more_frags = (*pos & 0x80) >> 7; 3331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos++; 3341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* Comeback Delay */ 3371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (pos + 2 > data + len) 3381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 3391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt comeback_delay = WPA_GET_LE16(pos); 3401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos += 2; 3411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* Advertisement Protocol element */ 3431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (pos + 2 > data + len || pos + 2 + pos[1] > data + len) { 3441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: No room for Advertisement " 3451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "Protocol element in the response from " MACSTR, 3461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MAC2STR(sa)); 3471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 3481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (*pos != WLAN_EID_ADV_PROTO) { 3511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Unexpected Advertisement " 3521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "Protocol element ID %u in response from " MACSTR, 3531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *pos, MAC2STR(sa)); 3541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 3551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt adv_proto = pos; 3581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos += 2 + pos[1]; 3591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* Query Response Length */ 3611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (pos + 2 > data + len) { 3621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: No room for GAS Response Length"); 3631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 3641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt resp_len = WPA_GET_LE16(pos); 3661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos += 2; 3671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (pos + resp_len > data + len) { 3691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Truncated Query Response in " 3701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "response from " MACSTR, MAC2STR(sa)); 3711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 3721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (pos + resp_len < data + len) { 3751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Ignore %u octets of extra data " 3761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "after Query Response from " MACSTR, 3771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt (unsigned int) (data + len - pos - resp_len), 3781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MAC2STR(sa)); 3791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (action == WLAN_PA_GAS_COMEBACK_RESP) 3821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_rx_comeback(gas, query, adv_proto, pos, resp_len, 3831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt frag_id, more_frags, comeback_delay); 3841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt else 3851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_rx_initial(gas, query, adv_proto, pos, resp_len, 3861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt comeback_delay); 3871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 3891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 3901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_timeout(void *eloop_data, void *user_ctx) 3931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 3941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query *gas = eloop_data; 3951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query = user_ctx; 3961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR, 3981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MAC2STR(query->addr)); 3991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_TIMEOUT); 4001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 4011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int gas_query_dialog_token_available(struct gas_query *gas, 4041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *dst, u8 dialog_token) 4051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 4061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *q; 4071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { 4081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 && 4091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dialog_token == q->dialog_token) 4101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 4111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 4121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 1; 4141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 4151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint gas_query_req(struct gas_query *gas, const u8 *dst, int freq, 4181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct wpabuf *req, 4191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt void (*cb)(void *ctx, const u8 *dst, u8 dialog_token, 4201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt enum gas_query_result result, 4211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const struct wpabuf *adv_proto, 4221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const struct wpabuf *resp, u16 status_code), 4231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt void *ctx) 4241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 4251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query; 4261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt int dialog_token; 4271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (wpabuf_len(req) < 3) 4291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return -1; 4301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (dialog_token = 0; dialog_token < 256; dialog_token++) { 4321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (gas_query_dialog_token_available(gas, dst, dialog_token)) 4331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt break; 4341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 4351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (dialog_token == 256) 4361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return -1; /* Too many pending queries */ 4371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query = os_zalloc(sizeof(*query)); 4391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (query == NULL) 4401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return -1; 4411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcpy(query->addr, dst, ETH_ALEN); 4431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->dialog_token = dialog_token; 4441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->freq = freq; 4451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->cb = cb; 4461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->ctx = ctx; 4471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dl_list_add(&gas->pending, &query->list); 4481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *(wpabuf_mhead_u8(req) + 2) = dialog_token; 4501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Starting request for " MACSTR 4521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt " dialog_token %u", MAC2STR(dst), dialog_token); 4531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (gas_query_tx(gas, query, req) < 0) { 4541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " 4551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MACSTR, MAC2STR(query->addr)); 4561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(query); 4571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return -1; 4581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 4591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt eloop_register_timeout(GAS_QUERY_TIMEOUT, 0, gas_query_timeout, 4611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas, query); 4621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return dialog_token; 4641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 4651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtvoid gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token) 4681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 4691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query; 4701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query = gas_query_get_pending(gas, dst, dialog_token); 4721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (query) 4731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_CANCELLED); 4741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 476