11f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/* 21f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Generic advertisement service (GAS) query 31f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Copyright (c) 2009, Atheros Communications 41846323989242844f0e857458a8939fa5836429cDmitry Shmidt * Copyright (c) 2011-2014, Qualcomm Atheros, Inc. 5fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi> 61f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * 7c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 8c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 91f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */ 101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "includes.h" 121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "common.h" 141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "utils/eloop.h" 151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "common/ieee802_11_defs.h" 161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "common/gas.h" 17fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt#include "common/wpa_ctrl.h" 181846323989242844f0e857458a8939fa5836429cDmitry Shmidt#include "rsn_supp/wpa.h" 191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "wpa_supplicant_i.h" 201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "driver_i.h" 211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "offchannel.h" 221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "gas_query.h" 231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 25a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/** GAS query timeout in seconds */ 26b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt#define GAS_QUERY_TIMEOUT_PERIOD 2 271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 29a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/** 30a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * struct gas_query_pending - Pending GAS query 31a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */ 321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct gas_query_pending { 331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct dl_list list; 34fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt struct gas_query *gas; 351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 addr[ETH_ALEN]; 361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 dialog_token; 371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 next_frag_id; 381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt unsigned int wait_comeback:1; 391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt unsigned int offchannel_tx_started:1; 401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt int freq; 411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u16 status_code; 42051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct wpabuf *req; 431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct wpabuf *adv_proto; 441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct wpabuf *resp; 45f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt struct os_reltime last_oper; 461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt void (*cb)(void *ctx, const u8 *dst, u8 dialog_token, 471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt enum gas_query_result result, 481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const struct wpabuf *adv_proto, 491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const struct wpabuf *resp, u16 status_code); 501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt void *ctx; 511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}; 521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 53a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/** 54a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * struct gas_query - Internal GAS query data 55a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */ 561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct gas_query { 571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct wpa_supplicant *wpa_s; 581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct dl_list pending; /* struct gas_query_pending */ 59051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct gas_query_pending *current; 60fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt struct wpa_radio_work *work; 611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}; 621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx); 651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_timeout(void *eloop_data, void *user_ctx); 661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 68f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic int ms_from_time(struct os_reltime *last) 69f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{ 70f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt struct os_reltime now, res; 71f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 72f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_get_reltime(&now); 73f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_reltime_sub(&now, last, &res); 74f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return res.sec * 1000 + res.usec / 1000; 75f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt} 76f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 77f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 78a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/** 79a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * gas_query_init - Initialize GAS query component 80a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data 81a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: Pointer to GAS query data or %NULL on failure 82a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */ 831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct gas_query * gas_query_init(struct wpa_supplicant *wpa_s) 841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query *gas; 861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas = os_zalloc(sizeof(*gas)); 881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (gas == NULL) 891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return NULL; 901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas->wpa_s = wpa_s; 921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dl_list_init(&gas->pending); 931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return gas; 951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 98fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidtstatic const char * gas_result_txt(enum gas_query_result result) 99fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt{ 100fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt switch (result) { 101fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt case GAS_QUERY_SUCCESS: 102fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt return "SUCCESS"; 103fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt case GAS_QUERY_FAILURE: 104fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt return "FAILURE"; 105fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt case GAS_QUERY_TIMEOUT: 106fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt return "TIMEOUT"; 107fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt case GAS_QUERY_PEER_ERROR: 108fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt return "PEER_ERROR"; 109fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt case GAS_QUERY_INTERNAL_ERROR: 110fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt return "INTERNAL_ERROR"; 111fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt case GAS_QUERY_CANCELLED: 112fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt return "CANCELLED"; 113fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt case GAS_QUERY_DELETED_AT_DEINIT: 114fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt return "DELETED_AT_DEINIT"; 115fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt } 116fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 117fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt return "N/A"; 118fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt} 119fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 120fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 121fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidtstatic void gas_query_free(struct gas_query_pending *query, int del_list) 122fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt{ 123fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt struct gas_query *gas = query->gas; 124fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 125fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (del_list) 126fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt dl_list_del(&query->list); 127fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 128fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (gas->work && gas->work->ctx == query) { 129fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt radio_work_done(gas->work); 130fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt gas->work = NULL; 131fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt } 132fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 133fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpabuf_free(query->req); 134fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpabuf_free(query->adv_proto); 135fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpabuf_free(query->resp); 136fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt os_free(query); 137fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt} 138fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 139fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 1401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_done(struct gas_query *gas, 1411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query, 1421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt enum gas_query_result result) 1431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 144fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_DONE "addr=" MACSTR 145fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt " dialog_token=%u freq=%d status_code=%u result=%s", 146fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt MAC2STR(query->addr), query->dialog_token, query->freq, 147fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt query->status_code, gas_result_txt(result)); 148051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (gas->current == query) 149051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt gas->current = NULL; 1501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (query->offchannel_tx_started) 1511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt offchannel_send_action_done(gas->wpa_s); 1521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); 1531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt eloop_cancel_timeout(gas_query_timeout, gas, query); 1541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dl_list_del(&query->list); 1551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->cb(query->ctx, query->addr, query->dialog_token, result, 1561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->adv_proto, query->resp, query->status_code); 157fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt gas_query_free(query, 0); 1581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 1591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 161a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/** 162a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * gas_query_deinit - Deinitialize GAS query component 163a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @gas: GAS query data from gas_query_init() 164a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */ 1651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtvoid gas_query_deinit(struct gas_query *gas) 1661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 1671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query, *next; 1681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (gas == NULL) 1701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 1711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dl_list_for_each_safe(query, next, &gas->pending, 1731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending, list) 1741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_DELETED_AT_DEINIT); 1751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(gas); 1771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 1781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic struct gas_query_pending * 1811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtgas_query_get_pending(struct gas_query *gas, const u8 *addr, u8 dialog_token) 1821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 1831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *q; 1841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { 1851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (os_memcmp(q->addr, addr, ETH_ALEN) == 0 && 1861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt q->dialog_token == dialog_token) 1871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return q; 1881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 1891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return NULL; 1901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 1911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int gas_query_append(struct gas_query_pending *query, const u8 *data, 1941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t len) 1951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 1961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (wpabuf_resize(&query->resp, len) < 0) { 1971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: No memory to store the response"); 1981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return -1; 1991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 2001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpabuf_put_data(query->resp, data, len); 2011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 2021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 2031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 205051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic void gas_query_tx_status(struct wpa_supplicant *wpa_s, 206051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt unsigned int freq, const u8 *dst, 207051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt const u8 *src, const u8 *bssid, 208051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt const u8 *data, size_t data_len, 209051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt enum offchannel_send_action_result result) 210051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 211051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct gas_query_pending *query; 212051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct gas_query *gas = wpa_s->gas; 213f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt int dur; 214051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 215051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (gas->current == NULL) { 216051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Unexpected TX status: freq=%u dst=" 217051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt MACSTR " result=%d - no query in progress", 218051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt freq, MAC2STR(dst), result); 219051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 220051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 221051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 222051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt query = gas->current; 223051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 224f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt dur = ms_from_time(&query->last_oper); 225051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR 226f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt " result=%d query=%p dialog_token=%u dur=%d ms", 227f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt freq, MAC2STR(dst), result, query, query->dialog_token, dur); 228051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (os_memcmp(dst, query->addr, ETH_ALEN) != 0) { 229051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination"); 230051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 231051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 232f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_get_reltime(&query->last_oper); 233051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 234051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (result == OFFCHANNEL_SEND_ACTION_SUCCESS) { 235051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt eloop_cancel_timeout(gas_query_timeout, gas, query); 236051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, 237051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt gas_query_timeout, gas, query); 238051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 239051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (result == OFFCHANNEL_SEND_ACTION_FAILED) { 240051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt eloop_cancel_timeout(gas_query_timeout, gas, query); 241051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt eloop_register_timeout(0, 0, gas_query_timeout, gas, query); 242051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 243051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 244051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 245051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 2461846323989242844f0e857458a8939fa5836429cDmitry Shmidtstatic int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr) 2471846323989242844f0e857458a8939fa5836429cDmitry Shmidt{ 2481846323989242844f0e857458a8939fa5836429cDmitry Shmidt if (wpa_s->current_ssid == NULL || 2491846323989242844f0e857458a8939fa5836429cDmitry Shmidt wpa_s->wpa_state < WPA_4WAY_HANDSHAKE || 2501846323989242844f0e857458a8939fa5836429cDmitry Shmidt os_memcmp(addr, wpa_s->bssid, ETH_ALEN) != 0) 2511846323989242844f0e857458a8939fa5836429cDmitry Shmidt return 0; 2521846323989242844f0e857458a8939fa5836429cDmitry Shmidt return wpa_sm_pmf_enabled(wpa_s->wpa); 2531846323989242844f0e857458a8939fa5836429cDmitry Shmidt} 2541846323989242844f0e857458a8939fa5836429cDmitry Shmidt 2551846323989242844f0e857458a8939fa5836429cDmitry Shmidt 2561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, 2571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct wpabuf *req) 2581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 259623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt unsigned int wait_time; 2601846323989242844f0e857458a8939fa5836429cDmitry Shmidt int res, prot = pmf_in_use(gas->wpa_s, query->addr); 2611846323989242844f0e857458a8939fa5836429cDmitry Shmidt 2621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u " 2631846323989242844f0e857458a8939fa5836429cDmitry Shmidt "freq=%d prot=%d", MAC2STR(query->addr), 2641846323989242844f0e857458a8939fa5836429cDmitry Shmidt (unsigned int) wpabuf_len(req), query->freq, prot); 2651846323989242844f0e857458a8939fa5836429cDmitry Shmidt if (prot) { 2661846323989242844f0e857458a8939fa5836429cDmitry Shmidt u8 *categ = wpabuf_mhead_u8(req); 2671846323989242844f0e857458a8939fa5836429cDmitry Shmidt *categ = WLAN_ACTION_PROTECTED_DUAL; 2681846323989242844f0e857458a8939fa5836429cDmitry Shmidt } 269f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_get_reltime(&query->last_oper); 270623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt wait_time = 1000; 271623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt if (gas->wpa_s->max_remain_on_chan && 272623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt wait_time > gas->wpa_s->max_remain_on_chan) 273623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt wait_time = gas->wpa_s->max_remain_on_chan; 2741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt res = offchannel_send_action(gas->wpa_s, query->freq, query->addr, 2751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas->wpa_s->own_addr, query->addr, 276623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt wpabuf_head(req), wpabuf_len(req), 277623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt wait_time, gas_query_tx_status, 0); 2781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (res == 0) 2791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->offchannel_tx_started = 1; 2801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return res; 2811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 2821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_tx_comeback_req(struct gas_query *gas, 2851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query) 2861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 2871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct wpabuf *req; 2881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt req = gas_build_comeback_req(query->dialog_token); 2901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (req == NULL) { 2911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 2921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 2931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 2941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (gas_query_tx(gas, query, req) < 0) { 2961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " 2971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MACSTR, MAC2STR(query->addr)); 2981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 2991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpabuf_free(req); 3021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 3031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx) 3061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 3071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query *gas = eloop_data; 3081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query = user_ctx; 3091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Comeback timeout for request to " MACSTR, 3111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MAC2STR(query->addr)); 3121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_tx_comeback_req(gas, query); 3131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 3141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_tx_comeback_req_delay(struct gas_query *gas, 3171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query, 3181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u16 comeback_delay) 3191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 3201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt unsigned int secs, usecs; 3211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt secs = (comeback_delay * 1024) / 1000000; 3231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt usecs = comeback_delay * 1024 - secs * 1000000; 3241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR 3251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt " in %u secs %u usecs", MAC2STR(query->addr), secs, usecs); 3261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); 3271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt eloop_register_timeout(secs, usecs, gas_query_tx_comeback_timeout, 3281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas, query); 3291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 3301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_rx_initial(struct gas_query *gas, 3331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query, 3341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *adv_proto, const u8 *resp, 3351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t len, u16 comeback_delay) 3361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 3371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Received initial response from " 3381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MACSTR " (dialog_token=%u comeback_delay=%u)", 3391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MAC2STR(query->addr), query->dialog_token, comeback_delay); 3401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->adv_proto = wpabuf_alloc_copy(adv_proto, 2 + adv_proto[1]); 3421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (query->adv_proto == NULL) { 3431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 3441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 3451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (comeback_delay) { 3481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->wait_comeback = 1; 3491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_tx_comeback_req_delay(gas, query, comeback_delay); 3501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 3511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* Query was completed without comeback mechanism */ 3541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (gas_query_append(query, resp, len) < 0) { 3551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 3561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 3571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_SUCCESS); 3601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 3611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_rx_comeback(struct gas_query *gas, 3641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query, 3651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *adv_proto, const u8 *resp, 3661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t len, u8 frag_id, u8 more_frags, 3671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u16 comeback_delay) 3681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 3691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Received comeback response from " 3701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MACSTR " (dialog_token=%u frag_id=%u more_frags=%u " 3711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "comeback_delay=%u)", 3721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MAC2STR(query->addr), query->dialog_token, frag_id, 3731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt more_frags, comeback_delay); 3741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) || 3761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcmp(adv_proto, wpabuf_head(query->adv_proto), 3771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpabuf_len(query->adv_proto)) != 0) { 3781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Advertisement Protocol changed " 3791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "between initial and comeback response from " 3801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MACSTR, MAC2STR(query->addr)); 3811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_PEER_ERROR); 3821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 3831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (comeback_delay) { 3861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (frag_id) { 3871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Invalid comeback response " 3881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "with non-zero frag_id and comeback_delay " 3891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "from " MACSTR, MAC2STR(query->addr)); 3901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_PEER_ERROR); 3911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 3921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_tx_comeback_req_delay(gas, query, comeback_delay); 3941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 3951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 3961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (frag_id != query->next_frag_id) { 3981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Unexpected frag_id in response " 3991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "from " MACSTR, MAC2STR(query->addr)); 400b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt if (frag_id + 1 == query->next_frag_id) { 401b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Drop frame as possible " 402b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt "retry of previous fragment"); 403b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt return; 404b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt } 4051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_PEER_ERROR); 4061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 4071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 4081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->next_frag_id++; 4091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (gas_query_append(query, resp, len) < 0) { 4111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); 4121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 4131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 4141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (more_frags) { 4161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_tx_comeback_req(gas, query); 4171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 4181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 4191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_SUCCESS); 4211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 4221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 424a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/** 4251846323989242844f0e857458a8939fa5836429cDmitry Shmidt * gas_query_rx - Indicate reception of a Public Action or Protected Dual frame 426a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @gas: GAS query data from gas_query_init() 427a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @da: Destination MAC address of the Action frame 428a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @sa: Source MAC address of the Action frame 429a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @bssid: BSSID of the Action frame 4301846323989242844f0e857458a8939fa5836429cDmitry Shmidt * @categ: Category of the Action frame 431a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @data: Payload of the Action frame 432a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @len: Length of @data 433a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @freq: Frequency (in MHz) on which the frame was received 434a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: 0 if the Public Action frame was a GAS frame or -1 if not 435a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */ 4361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, 4371846323989242844f0e857458a8939fa5836429cDmitry Shmidt const u8 *bssid, u8 categ, const u8 *data, size_t len, 4381846323989242844f0e857458a8939fa5836429cDmitry Shmidt int freq) 4391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 4401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query; 4411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 action, dialog_token, frag_id = 0, more_frags = 0; 4421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u16 comeback_delay, resp_len; 4431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *pos, *adv_proto; 4441846323989242844f0e857458a8939fa5836429cDmitry Shmidt int prot, pmf; 445fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int left; 4461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (gas == NULL || len < 4) 4481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return -1; 4491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4501846323989242844f0e857458a8939fa5836429cDmitry Shmidt prot = categ == WLAN_ACTION_PROTECTED_DUAL; 4511846323989242844f0e857458a8939fa5836429cDmitry Shmidt pmf = pmf_in_use(gas->wpa_s, bssid); 4521846323989242844f0e857458a8939fa5836429cDmitry Shmidt if (prot && !pmf) { 4531846323989242844f0e857458a8939fa5836429cDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Drop unexpected protected GAS frame when PMF is disabled"); 4541846323989242844f0e857458a8939fa5836429cDmitry Shmidt return 0; 4551846323989242844f0e857458a8939fa5836429cDmitry Shmidt } 4561846323989242844f0e857458a8939fa5836429cDmitry Shmidt if (!prot && pmf) { 4571846323989242844f0e857458a8939fa5836429cDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Drop unexpected unprotected GAS frame when PMF is enabled"); 4581846323989242844f0e857458a8939fa5836429cDmitry Shmidt return 0; 4591846323989242844f0e857458a8939fa5836429cDmitry Shmidt } 4601846323989242844f0e857458a8939fa5836429cDmitry Shmidt 4611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos = data; 4621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt action = *pos++; 4631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dialog_token = *pos++; 4641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (action != WLAN_PA_GAS_INITIAL_RESP && 4661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt action != WLAN_PA_GAS_COMEBACK_RESP) 4671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return -1; /* Not a GAS response */ 4681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query = gas_query_get_pending(gas, sa, dialog_token); 4701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (query == NULL) { 4711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR 4721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt " dialog token %u", MAC2STR(sa), dialog_token); 4731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return -1; 4741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 4751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 476f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Response in %d ms from " MACSTR, 477f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ms_from_time(&query->last_oper), MAC2STR(sa)); 478f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 4791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (query->wait_comeback && action == WLAN_PA_GAS_INITIAL_RESP) { 4801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Unexpected initial response from " 4811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MACSTR " dialog token %u when waiting for comeback " 4821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "response", MAC2STR(sa), dialog_token); 4831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 4841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 4851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (!query->wait_comeback && action == WLAN_PA_GAS_COMEBACK_RESP) { 4871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Unexpected comeback response from " 4881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MACSTR " dialog token %u when waiting for initial " 4891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "response", MAC2STR(sa), dialog_token); 4901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 4911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 4921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->status_code = WPA_GET_LE16(pos); 4941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos += 2; 4951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 4967d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt if (query->status_code == WLAN_STATUS_QUERY_RESP_OUTSTANDING && 4977d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt action == WLAN_PA_GAS_COMEBACK_RESP) { 4987d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Allow non-zero status for outstanding comeback response"); 4997d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt } else if (query->status_code != WLAN_STATUS_SUCCESS) { 5001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Query to " MACSTR " dialog token " 5011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "%u failed - status code %u", 5021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MAC2STR(sa), dialog_token, query->status_code); 5031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_FAILURE); 5041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 5051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 5061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (action == WLAN_PA_GAS_COMEBACK_RESP) { 5081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (pos + 1 > data + len) 5091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 5101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt frag_id = *pos & 0x7f; 5111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt more_frags = (*pos & 0x80) >> 7; 5121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos++; 5131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 5141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* Comeback Delay */ 5161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (pos + 2 > data + len) 5171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 5181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt comeback_delay = WPA_GET_LE16(pos); 5191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos += 2; 5201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* Advertisement Protocol element */ 5221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (pos + 2 > data + len || pos + 2 + pos[1] > data + len) { 5231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: No room for Advertisement " 5241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "Protocol element in the response from " MACSTR, 5251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt MAC2STR(sa)); 5261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 5271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 5281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (*pos != WLAN_EID_ADV_PROTO) { 5301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Unexpected Advertisement " 5311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "Protocol element ID %u in response from " MACSTR, 5321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *pos, MAC2STR(sa)); 5331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 5341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 5351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt adv_proto = pos; 5371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos += 2 + pos[1]; 5381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* Query Response Length */ 5401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (pos + 2 > data + len) { 5411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: No room for GAS Response Length"); 5421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 5431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 5441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt resp_len = WPA_GET_LE16(pos); 5451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos += 2; 5461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 547fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt left = data + len - pos; 548fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (resp_len > left) { 5491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Truncated Query Response in " 5501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "response from " MACSTR, MAC2STR(sa)); 5511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 5521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 5531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 554fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (resp_len < left) { 5551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Ignore %u octets of extra data " 5561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "after Query Response from " MACSTR, 557fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt left - resp_len, MAC2STR(sa)); 5581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 5591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (action == WLAN_PA_GAS_COMEBACK_RESP) 5611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_rx_comeback(gas, query, adv_proto, pos, resp_len, 5621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt frag_id, more_frags, comeback_delay); 5631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt else 5641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_rx_initial(gas, query, adv_proto, pos, resp_len, 5651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt comeback_delay); 5661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 5681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 5691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_query_timeout(void *eloop_data, void *user_ctx) 5721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 5731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query *gas = eloop_data; 5741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query = user_ctx; 5751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 576051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR 577051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt " dialog token %u", 578051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt MAC2STR(query->addr), query->dialog_token); 5791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_TIMEOUT); 5801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 5811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 583fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidtstatic int gas_query_dialog_token_available(struct gas_query *gas, 584fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt const u8 *dst, u8 dialog_token) 585051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 586fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt struct gas_query_pending *q; 587fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { 588fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 && 589fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt dialog_token == q->dialog_token) 590fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt return 0; 591fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt } 592fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 593fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt return 1; 594fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt} 595fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 596fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 597fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidtstatic void gas_query_start_cb(struct wpa_radio_work *work, int deinit) 598fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt{ 599fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt struct gas_query_pending *query = work->ctx; 600fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt struct gas_query *gas = query->gas; 601661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt struct wpa_supplicant *wpa_s = gas->wpa_s; 602fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 603fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (deinit) { 604bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt if (work->started) { 605bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt gas->work = NULL; 606bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_DELETED_AT_DEINIT); 607bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt return; 608bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt } 609bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt 610fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt gas_query_free(query, 1); 611051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 612051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 613051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 614661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt if (wpas_update_random_addr_disassoc(wpa_s) < 0) { 615661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt wpa_msg(wpa_s, MSG_INFO, 616661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt "Failed to assign random MAC address for GAS"); 617661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt gas_query_free(query, 1); 618661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt radio_work_done(work); 619661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt return; 620661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt } 621661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt 622fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt gas->work = work; 623fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 624051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (gas_query_tx(gas, query, query->req) < 0) { 625051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " 626051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt MACSTR, MAC2STR(query->addr)); 627fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt gas_query_free(query, 1); 628051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 629051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 630051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt gas->current = query; 631051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 632051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "GAS: Starting query timeout for dialog token %u", 633051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt query->dialog_token); 634051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, 635051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt gas_query_timeout, gas, query); 636051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 6371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 6381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 6391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 640a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/** 641a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * gas_query_req - Request a GAS query 642a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @gas: GAS query data from gas_query_init() 643a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @dst: Destination MAC address for the query 644a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @freq: Frequency (in MHz) for the channel on which to send the query 645051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * @req: GAS query payload (to be freed by gas_query module in case of success 646051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * return) 647a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @cb: Callback function for reporting GAS query result and response 648a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @ctx: Context pointer to use with the @cb call 649a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: dialog token (>= 0) on success or -1 on failure 650a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */ 6511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint gas_query_req(struct gas_query *gas, const u8 *dst, int freq, 6521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct wpabuf *req, 6531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt void (*cb)(void *ctx, const u8 *dst, u8 dialog_token, 6541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt enum gas_query_result result, 6551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const struct wpabuf *adv_proto, 6561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const struct wpabuf *resp, u16 status_code), 6571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt void *ctx) 6581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 6591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query; 6601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt int dialog_token; 661b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt static int next_start = 0; 6621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 6631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (wpabuf_len(req) < 3) 6641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return -1; 6651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 6661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (dialog_token = 0; dialog_token < 256; dialog_token++) { 667b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt if (gas_query_dialog_token_available( 668b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt gas, dst, (next_start + dialog_token) % 256)) 6691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt break; 6701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 6711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (dialog_token == 256) 6721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return -1; /* Too many pending queries */ 673b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt dialog_token = (next_start + dialog_token) % 256; 674b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt next_start = (dialog_token + 1) % 256; 6751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 6761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query = os_zalloc(sizeof(*query)); 6771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (query == NULL) 6781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return -1; 6791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 680fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt query->gas = gas; 6811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcpy(query->addr, dst, ETH_ALEN); 6821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->dialog_token = dialog_token; 6831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->freq = freq; 6841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->cb = cb; 6851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query->ctx = ctx; 686051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt query->req = req; 6871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dl_list_add(&gas->pending, &query->list); 6881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 6891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *(wpabuf_mhead_u8(req) + 2) = dialog_token; 6901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 691fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_START "addr=" MACSTR 692fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt " dialog_token=%u freq=%d", 693fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt MAC2STR(query->addr), query->dialog_token, query->freq); 6941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 695fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb, 696fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt query) < 0) { 697fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt gas_query_free(query, 1); 698fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt return -1; 699fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt } 7001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 7011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return dialog_token; 7021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 7031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 7041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 705a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/** 706a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * gas_query_cancel - Cancel a pending GAS query 707a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @gas: GAS query data from gas_query_init() 708a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @dst: Destination MAC address for the query 709a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @dialog_token: Dialog token from gas_query_req() 710a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */ 7111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtvoid gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token) 7121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 7131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct gas_query_pending *query; 7141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 7151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt query = gas_query_get_pending(gas, dst, dialog_token); 7161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (query) 7171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt gas_query_done(gas, query, GAS_QUERY_CANCELLED); 7181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 7191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 720