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