GAS: Delay GAS query Tx while another query is in progress
It would be possible to issue another GAS query when a previous one is still in progress and this could result in conflicting offchannel operations. Prevent that by delaying GAS query initiation until the previous operation has been completed. Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
7255983b59
commit
24c694b465
3 changed files with 47 additions and 15 deletions
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Generic advertisement service (GAS) query
|
||||
* Copyright (c) 2009, Atheros Communications
|
||||
* Copyright (c) 2011, Qualcomm Atheros
|
||||
* Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
|
@ -21,6 +21,8 @@
|
|||
|
||||
/** GAS query timeout in seconds */
|
||||
#define GAS_QUERY_TIMEOUT_PERIOD 2
|
||||
/** Retry period for GAS query requests in milliseconds */
|
||||
#define GAS_SERVICE_RETRY_PERIOD_MS 500
|
||||
|
||||
|
||||
/**
|
||||
|
@ -35,6 +37,7 @@ struct gas_query_pending {
|
|||
unsigned int offchannel_tx_started:1;
|
||||
int freq;
|
||||
u16 status_code;
|
||||
struct wpabuf *req;
|
||||
struct wpabuf *adv_proto;
|
||||
struct wpabuf *resp;
|
||||
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
|
||||
|
@ -50,11 +53,13 @@ struct gas_query_pending {
|
|||
struct gas_query {
|
||||
struct wpa_supplicant *wpa_s;
|
||||
struct dl_list pending; /* struct gas_query_pending */
|
||||
struct gas_query_pending *current;
|
||||
};
|
||||
|
||||
|
||||
static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
|
||||
static void gas_query_timeout(void *eloop_data, void *user_ctx);
|
||||
static void gas_service_timeout(void *eloop_data, void *user_ctx);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -81,13 +86,17 @@ static void gas_query_done(struct gas_query *gas,
|
|||
struct gas_query_pending *query,
|
||||
enum gas_query_result result)
|
||||
{
|
||||
if (gas->current == query)
|
||||
gas->current = NULL;
|
||||
if (query->offchannel_tx_started)
|
||||
offchannel_send_action_done(gas->wpa_s);
|
||||
eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
|
||||
eloop_cancel_timeout(gas_query_timeout, gas, query);
|
||||
eloop_cancel_timeout(gas_service_timeout, gas, query);
|
||||
dl_list_del(&query->list);
|
||||
query->cb(query->ctx, query->addr, query->dialog_token, result,
|
||||
query->adv_proto, query->resp, query->status_code);
|
||||
wpabuf_free(query->req);
|
||||
wpabuf_free(query->adv_proto);
|
||||
wpabuf_free(query->resp);
|
||||
os_free(query);
|
||||
|
@ -466,6 +475,35 @@ static void gas_query_timeout(void *eloop_data, void *user_ctx)
|
|||
}
|
||||
|
||||
|
||||
static void gas_service_timeout(void *eloop_data, void *user_ctx)
|
||||
{
|
||||
struct gas_query *gas = eloop_data;
|
||||
struct gas_query_pending *query = user_ctx;
|
||||
|
||||
if (gas->current) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Delaying GAS query Tx while another operation is in progress");
|
||||
eloop_register_timeout(
|
||||
GAS_SERVICE_RETRY_PERIOD_MS / 1000,
|
||||
(GAS_SERVICE_RETRY_PERIOD_MS % 1000) * 1000,
|
||||
gas_service_timeout, gas, query);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gas_query_tx(gas, query, query->req) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
|
||||
MACSTR, MAC2STR(query->addr));
|
||||
dl_list_del(&query->list);
|
||||
wpabuf_free(query->req);
|
||||
os_free(query);
|
||||
return;
|
||||
}
|
||||
gas->current = query;
|
||||
|
||||
eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
|
||||
gas_query_timeout, gas, query);
|
||||
}
|
||||
|
||||
|
||||
static int gas_query_dialog_token_available(struct gas_query *gas,
|
||||
const u8 *dst, u8 dialog_token)
|
||||
{
|
||||
|
@ -485,7 +523,8 @@ static int gas_query_dialog_token_available(struct gas_query *gas,
|
|||
* @gas: GAS query data from gas_query_init()
|
||||
* @dst: Destination MAC address for the query
|
||||
* @freq: Frequency (in MHz) for the channel on which to send the query
|
||||
* @req: GAS query payload
|
||||
* @req: GAS query payload (to be freed by gas_query module in case of success
|
||||
* return)
|
||||
* @cb: Callback function for reporting GAS query result and response
|
||||
* @ctx: Context pointer to use with the @cb call
|
||||
* Returns: dialog token (>= 0) on success or -1 on failure
|
||||
|
@ -524,22 +563,15 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
|
|||
query->freq = freq;
|
||||
query->cb = cb;
|
||||
query->ctx = ctx;
|
||||
query->req = req;
|
||||
dl_list_add(&gas->pending, &query->list);
|
||||
|
||||
*(wpabuf_mhead_u8(req) + 2) = dialog_token;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "GAS: Starting request for " MACSTR
|
||||
" dialog_token %u", MAC2STR(dst), dialog_token);
|
||||
if (gas_query_tx(gas, query, req) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
|
||||
MACSTR, MAC2STR(query->addr));
|
||||
dl_list_del(&query->list);
|
||||
os_free(query);
|
||||
return -1;
|
||||
}
|
||||
|
||||
eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout,
|
||||
gas, query);
|
||||
eloop_register_timeout(0, 0, gas_service_timeout, gas, query);
|
||||
|
||||
return dialog_token;
|
||||
}
|
||||
|
|
|
@ -125,12 +125,12 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
|
|||
res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
|
||||
wpabuf_free(buf);
|
||||
ret = -1;
|
||||
} else
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
|
||||
"%u", res);
|
||||
|
||||
wpabuf_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -244,6 +244,7 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
|
|||
interworking_anqp_resp_cb, wpa_s);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
|
||||
wpabuf_free(buf);
|
||||
ret = -1;
|
||||
eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s,
|
||||
NULL);
|
||||
|
@ -251,7 +252,6 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
|
|||
wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
|
||||
"%u", res);
|
||||
|
||||
wpabuf_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1877,12 +1877,12 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
|
|||
res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
|
||||
wpabuf_free(buf);
|
||||
ret = -1;
|
||||
} else
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
|
||||
"%u", res);
|
||||
|
||||
wpabuf_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2177,11 +2177,11 @@ int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
|
|||
res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request");
|
||||
wpabuf_free(buf);
|
||||
ret = -1;
|
||||
} else
|
||||
wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token "
|
||||
"%u", res);
|
||||
|
||||
wpabuf_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue