aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyeyoon Park <kyeyoonp@qca.qualcomm.com>2013-10-21 10:13:42 (GMT)
committerJouni Malinen <j@w1.fi>2013-10-21 10:13:42 (GMT)
commit24c694b465ea9535436caf85c0e71d4346e15abd (patch)
treebf5257698e287d944707b8fcc2849f123168b4be
parent7255983b59adb56a74f6c3a97ae9171e1481a12f (diff)
downloadhostap-24c694b465ea9535436caf85c0e71d4346e15abd.zip
hostap-24c694b465ea9535436caf85c0e71d4346e15abd.tar.gz
hostap-24c694b465ea9535436caf85c0e71d4346e15abd.tar.bz2
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>
-rw-r--r--wpa_supplicant/gas_query.c54
-rw-r--r--wpa_supplicant/hs20_supplicant.c2
-rw-r--r--wpa_supplicant/interworking.c6
3 files changed, 47 insertions, 15 deletions
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 7ae686e..a4e675d 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -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;
}
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 4048cf7..5f30313 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -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;
}
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index ba2b2fd..e294917 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -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;
}