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