gas_query.c revision 1.1.1.2 1 1.1 christos /*
2 1.1 christos * Generic advertisement service (GAS) query
3 1.1 christos * Copyright (c) 2009, Atheros Communications
4 1.1 christos * Copyright (c) 2011, Qualcomm Atheros
5 1.1 christos *
6 1.1.1.2 christos * This software may be distributed under the terms of the BSD license.
7 1.1.1.2 christos * See README for more details.
8 1.1 christos */
9 1.1 christos
10 1.1 christos #include "includes.h"
11 1.1 christos
12 1.1 christos #include "common.h"
13 1.1 christos #include "utils/eloop.h"
14 1.1 christos #include "common/ieee802_11_defs.h"
15 1.1 christos #include "common/gas.h"
16 1.1 christos #include "wpa_supplicant_i.h"
17 1.1 christos #include "driver_i.h"
18 1.1 christos #include "offchannel.h"
19 1.1 christos #include "gas_query.h"
20 1.1 christos
21 1.1 christos
22 1.1.1.2 christos /** GAS query timeout in seconds */
23 1.1.1.2 christos #define GAS_QUERY_TIMEOUT_PERIOD 5
24 1.1 christos
25 1.1 christos
26 1.1.1.2 christos /**
27 1.1.1.2 christos * struct gas_query_pending - Pending GAS query
28 1.1.1.2 christos */
29 1.1 christos struct gas_query_pending {
30 1.1 christos struct dl_list list;
31 1.1 christos u8 addr[ETH_ALEN];
32 1.1 christos u8 dialog_token;
33 1.1 christos u8 next_frag_id;
34 1.1 christos unsigned int wait_comeback:1;
35 1.1 christos unsigned int offchannel_tx_started:1;
36 1.1 christos int freq;
37 1.1 christos u16 status_code;
38 1.1 christos struct wpabuf *adv_proto;
39 1.1 christos struct wpabuf *resp;
40 1.1 christos void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
41 1.1 christos enum gas_query_result result,
42 1.1 christos const struct wpabuf *adv_proto,
43 1.1 christos const struct wpabuf *resp, u16 status_code);
44 1.1 christos void *ctx;
45 1.1 christos };
46 1.1 christos
47 1.1.1.2 christos /**
48 1.1.1.2 christos * struct gas_query - Internal GAS query data
49 1.1.1.2 christos */
50 1.1 christos struct gas_query {
51 1.1 christos struct wpa_supplicant *wpa_s;
52 1.1 christos struct dl_list pending; /* struct gas_query_pending */
53 1.1 christos };
54 1.1 christos
55 1.1 christos
56 1.1 christos static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
57 1.1 christos static void gas_query_timeout(void *eloop_data, void *user_ctx);
58 1.1 christos
59 1.1 christos
60 1.1.1.2 christos /**
61 1.1.1.2 christos * gas_query_init - Initialize GAS query component
62 1.1.1.2 christos * @wpa_s: Pointer to wpa_supplicant data
63 1.1.1.2 christos * Returns: Pointer to GAS query data or %NULL on failure
64 1.1.1.2 christos */
65 1.1 christos struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s)
66 1.1 christos {
67 1.1 christos struct gas_query *gas;
68 1.1 christos
69 1.1 christos gas = os_zalloc(sizeof(*gas));
70 1.1 christos if (gas == NULL)
71 1.1 christos return NULL;
72 1.1 christos
73 1.1 christos gas->wpa_s = wpa_s;
74 1.1 christos dl_list_init(&gas->pending);
75 1.1 christos
76 1.1 christos return gas;
77 1.1 christos }
78 1.1 christos
79 1.1 christos
80 1.1 christos static void gas_query_done(struct gas_query *gas,
81 1.1 christos struct gas_query_pending *query,
82 1.1 christos enum gas_query_result result)
83 1.1 christos {
84 1.1 christos if (query->offchannel_tx_started)
85 1.1 christos offchannel_send_action_done(gas->wpa_s);
86 1.1 christos eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
87 1.1 christos eloop_cancel_timeout(gas_query_timeout, gas, query);
88 1.1 christos dl_list_del(&query->list);
89 1.1 christos query->cb(query->ctx, query->addr, query->dialog_token, result,
90 1.1 christos query->adv_proto, query->resp, query->status_code);
91 1.1 christos wpabuf_free(query->adv_proto);
92 1.1 christos wpabuf_free(query->resp);
93 1.1 christos os_free(query);
94 1.1 christos }
95 1.1 christos
96 1.1 christos
97 1.1.1.2 christos /**
98 1.1.1.2 christos * gas_query_deinit - Deinitialize GAS query component
99 1.1.1.2 christos * @gas: GAS query data from gas_query_init()
100 1.1.1.2 christos */
101 1.1 christos void gas_query_deinit(struct gas_query *gas)
102 1.1 christos {
103 1.1 christos struct gas_query_pending *query, *next;
104 1.1 christos
105 1.1 christos if (gas == NULL)
106 1.1 christos return;
107 1.1 christos
108 1.1 christos dl_list_for_each_safe(query, next, &gas->pending,
109 1.1 christos struct gas_query_pending, list)
110 1.1 christos gas_query_done(gas, query, GAS_QUERY_DELETED_AT_DEINIT);
111 1.1 christos
112 1.1 christos os_free(gas);
113 1.1 christos }
114 1.1 christos
115 1.1 christos
116 1.1 christos static struct gas_query_pending *
117 1.1 christos gas_query_get_pending(struct gas_query *gas, const u8 *addr, u8 dialog_token)
118 1.1 christos {
119 1.1 christos struct gas_query_pending *q;
120 1.1 christos dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
121 1.1 christos if (os_memcmp(q->addr, addr, ETH_ALEN) == 0 &&
122 1.1 christos q->dialog_token == dialog_token)
123 1.1 christos return q;
124 1.1 christos }
125 1.1 christos return NULL;
126 1.1 christos }
127 1.1 christos
128 1.1 christos
129 1.1 christos static int gas_query_append(struct gas_query_pending *query, const u8 *data,
130 1.1 christos size_t len)
131 1.1 christos {
132 1.1 christos if (wpabuf_resize(&query->resp, len) < 0) {
133 1.1 christos wpa_printf(MSG_DEBUG, "GAS: No memory to store the response");
134 1.1 christos return -1;
135 1.1 christos }
136 1.1 christos wpabuf_put_data(query->resp, data, len);
137 1.1 christos return 0;
138 1.1 christos }
139 1.1 christos
140 1.1 christos
141 1.1 christos static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
142 1.1 christos struct wpabuf *req)
143 1.1 christos {
144 1.1 christos int res;
145 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
146 1.1 christos "freq=%d", MAC2STR(query->addr),
147 1.1 christos (unsigned int) wpabuf_len(req), query->freq);
148 1.1 christos res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
149 1.1 christos gas->wpa_s->own_addr, query->addr,
150 1.1 christos wpabuf_head(req), wpabuf_len(req), 1000,
151 1.1 christos NULL, 0);
152 1.1 christos if (res == 0)
153 1.1 christos query->offchannel_tx_started = 1;
154 1.1 christos return res;
155 1.1 christos }
156 1.1 christos
157 1.1 christos
158 1.1 christos static void gas_query_tx_comeback_req(struct gas_query *gas,
159 1.1 christos struct gas_query_pending *query)
160 1.1 christos {
161 1.1 christos struct wpabuf *req;
162 1.1 christos
163 1.1 christos req = gas_build_comeback_req(query->dialog_token);
164 1.1 christos if (req == NULL) {
165 1.1 christos gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
166 1.1 christos return;
167 1.1 christos }
168 1.1 christos
169 1.1 christos if (gas_query_tx(gas, query, req) < 0) {
170 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
171 1.1 christos MACSTR, MAC2STR(query->addr));
172 1.1 christos gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
173 1.1 christos }
174 1.1 christos
175 1.1 christos wpabuf_free(req);
176 1.1 christos }
177 1.1 christos
178 1.1 christos
179 1.1 christos static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx)
180 1.1 christos {
181 1.1 christos struct gas_query *gas = eloop_data;
182 1.1 christos struct gas_query_pending *query = user_ctx;
183 1.1 christos
184 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Comeback timeout for request to " MACSTR,
185 1.1 christos MAC2STR(query->addr));
186 1.1 christos gas_query_tx_comeback_req(gas, query);
187 1.1 christos }
188 1.1 christos
189 1.1 christos
190 1.1 christos static void gas_query_tx_comeback_req_delay(struct gas_query *gas,
191 1.1 christos struct gas_query_pending *query,
192 1.1 christos u16 comeback_delay)
193 1.1 christos {
194 1.1 christos unsigned int secs, usecs;
195 1.1 christos
196 1.1 christos secs = (comeback_delay * 1024) / 1000000;
197 1.1 christos usecs = comeback_delay * 1024 - secs * 1000000;
198 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR
199 1.1 christos " in %u secs %u usecs", MAC2STR(query->addr), secs, usecs);
200 1.1 christos eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
201 1.1 christos eloop_register_timeout(secs, usecs, gas_query_tx_comeback_timeout,
202 1.1 christos gas, query);
203 1.1 christos }
204 1.1 christos
205 1.1 christos
206 1.1 christos static void gas_query_rx_initial(struct gas_query *gas,
207 1.1 christos struct gas_query_pending *query,
208 1.1 christos const u8 *adv_proto, const u8 *resp,
209 1.1 christos size_t len, u16 comeback_delay)
210 1.1 christos {
211 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Received initial response from "
212 1.1 christos MACSTR " (dialog_token=%u comeback_delay=%u)",
213 1.1 christos MAC2STR(query->addr), query->dialog_token, comeback_delay);
214 1.1 christos
215 1.1 christos query->adv_proto = wpabuf_alloc_copy(adv_proto, 2 + adv_proto[1]);
216 1.1 christos if (query->adv_proto == NULL) {
217 1.1 christos gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
218 1.1 christos return;
219 1.1 christos }
220 1.1 christos
221 1.1 christos if (comeback_delay) {
222 1.1 christos query->wait_comeback = 1;
223 1.1 christos gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
224 1.1 christos return;
225 1.1 christos }
226 1.1 christos
227 1.1 christos /* Query was completed without comeback mechanism */
228 1.1 christos if (gas_query_append(query, resp, len) < 0) {
229 1.1 christos gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
230 1.1 christos return;
231 1.1 christos }
232 1.1 christos
233 1.1 christos gas_query_done(gas, query, GAS_QUERY_SUCCESS);
234 1.1 christos }
235 1.1 christos
236 1.1 christos
237 1.1 christos static void gas_query_rx_comeback(struct gas_query *gas,
238 1.1 christos struct gas_query_pending *query,
239 1.1 christos const u8 *adv_proto, const u8 *resp,
240 1.1 christos size_t len, u8 frag_id, u8 more_frags,
241 1.1 christos u16 comeback_delay)
242 1.1 christos {
243 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Received comeback response from "
244 1.1 christos MACSTR " (dialog_token=%u frag_id=%u more_frags=%u "
245 1.1 christos "comeback_delay=%u)",
246 1.1 christos MAC2STR(query->addr), query->dialog_token, frag_id,
247 1.1 christos more_frags, comeback_delay);
248 1.1 christos
249 1.1 christos if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) ||
250 1.1 christos os_memcmp(adv_proto, wpabuf_head(query->adv_proto),
251 1.1 christos wpabuf_len(query->adv_proto)) != 0) {
252 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Advertisement Protocol changed "
253 1.1 christos "between initial and comeback response from "
254 1.1 christos MACSTR, MAC2STR(query->addr));
255 1.1 christos gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
256 1.1 christos return;
257 1.1 christos }
258 1.1 christos
259 1.1 christos if (comeback_delay) {
260 1.1 christos if (frag_id) {
261 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Invalid comeback response "
262 1.1 christos "with non-zero frag_id and comeback_delay "
263 1.1 christos "from " MACSTR, MAC2STR(query->addr));
264 1.1 christos gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
265 1.1 christos return;
266 1.1 christos }
267 1.1 christos gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
268 1.1 christos return;
269 1.1 christos }
270 1.1 christos
271 1.1 christos if (frag_id != query->next_frag_id) {
272 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Unexpected frag_id in response "
273 1.1 christos "from " MACSTR, MAC2STR(query->addr));
274 1.1 christos gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
275 1.1 christos return;
276 1.1 christos }
277 1.1 christos query->next_frag_id++;
278 1.1 christos
279 1.1 christos if (gas_query_append(query, resp, len) < 0) {
280 1.1 christos gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
281 1.1 christos return;
282 1.1 christos }
283 1.1 christos
284 1.1 christos if (more_frags) {
285 1.1 christos gas_query_tx_comeback_req(gas, query);
286 1.1 christos return;
287 1.1 christos }
288 1.1 christos
289 1.1 christos gas_query_done(gas, query, GAS_QUERY_SUCCESS);
290 1.1 christos }
291 1.1 christos
292 1.1 christos
293 1.1.1.2 christos /**
294 1.1.1.2 christos * gas_query_rx - Indicate reception of a Public Action frame
295 1.1.1.2 christos * @gas: GAS query data from gas_query_init()
296 1.1.1.2 christos * @da: Destination MAC address of the Action frame
297 1.1.1.2 christos * @sa: Source MAC address of the Action frame
298 1.1.1.2 christos * @bssid: BSSID of the Action frame
299 1.1.1.2 christos * @data: Payload of the Action frame
300 1.1.1.2 christos * @len: Length of @data
301 1.1.1.2 christos * @freq: Frequency (in MHz) on which the frame was received
302 1.1.1.2 christos * Returns: 0 if the Public Action frame was a GAS frame or -1 if not
303 1.1.1.2 christos */
304 1.1 christos int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
305 1.1 christos const u8 *bssid, const u8 *data, size_t len, int freq)
306 1.1 christos {
307 1.1 christos struct gas_query_pending *query;
308 1.1 christos u8 action, dialog_token, frag_id = 0, more_frags = 0;
309 1.1 christos u16 comeback_delay, resp_len;
310 1.1 christos const u8 *pos, *adv_proto;
311 1.1 christos
312 1.1 christos if (gas == NULL || len < 4)
313 1.1 christos return -1;
314 1.1 christos
315 1.1 christos pos = data;
316 1.1 christos action = *pos++;
317 1.1 christos dialog_token = *pos++;
318 1.1 christos
319 1.1 christos if (action != WLAN_PA_GAS_INITIAL_RESP &&
320 1.1 christos action != WLAN_PA_GAS_COMEBACK_RESP)
321 1.1 christos return -1; /* Not a GAS response */
322 1.1 christos
323 1.1 christos query = gas_query_get_pending(gas, sa, dialog_token);
324 1.1 christos if (query == NULL) {
325 1.1 christos wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR
326 1.1 christos " dialog token %u", MAC2STR(sa), dialog_token);
327 1.1 christos return -1;
328 1.1 christos }
329 1.1 christos
330 1.1 christos if (query->wait_comeback && action == WLAN_PA_GAS_INITIAL_RESP) {
331 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Unexpected initial response from "
332 1.1 christos MACSTR " dialog token %u when waiting for comeback "
333 1.1 christos "response", MAC2STR(sa), dialog_token);
334 1.1 christos return 0;
335 1.1 christos }
336 1.1 christos
337 1.1 christos if (!query->wait_comeback && action == WLAN_PA_GAS_COMEBACK_RESP) {
338 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Unexpected comeback response from "
339 1.1 christos MACSTR " dialog token %u when waiting for initial "
340 1.1 christos "response", MAC2STR(sa), dialog_token);
341 1.1 christos return 0;
342 1.1 christos }
343 1.1 christos
344 1.1 christos query->status_code = WPA_GET_LE16(pos);
345 1.1 christos pos += 2;
346 1.1 christos
347 1.1 christos if (query->status_code != WLAN_STATUS_SUCCESS) {
348 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Query to " MACSTR " dialog token "
349 1.1 christos "%u failed - status code %u",
350 1.1 christos MAC2STR(sa), dialog_token, query->status_code);
351 1.1 christos gas_query_done(gas, query, GAS_QUERY_FAILURE);
352 1.1 christos return 0;
353 1.1 christos }
354 1.1 christos
355 1.1 christos if (action == WLAN_PA_GAS_COMEBACK_RESP) {
356 1.1 christos if (pos + 1 > data + len)
357 1.1 christos return 0;
358 1.1 christos frag_id = *pos & 0x7f;
359 1.1 christos more_frags = (*pos & 0x80) >> 7;
360 1.1 christos pos++;
361 1.1 christos }
362 1.1 christos
363 1.1 christos /* Comeback Delay */
364 1.1 christos if (pos + 2 > data + len)
365 1.1 christos return 0;
366 1.1 christos comeback_delay = WPA_GET_LE16(pos);
367 1.1 christos pos += 2;
368 1.1 christos
369 1.1 christos /* Advertisement Protocol element */
370 1.1 christos if (pos + 2 > data + len || pos + 2 + pos[1] > data + len) {
371 1.1 christos wpa_printf(MSG_DEBUG, "GAS: No room for Advertisement "
372 1.1 christos "Protocol element in the response from " MACSTR,
373 1.1 christos MAC2STR(sa));
374 1.1 christos return 0;
375 1.1 christos }
376 1.1 christos
377 1.1 christos if (*pos != WLAN_EID_ADV_PROTO) {
378 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Unexpected Advertisement "
379 1.1 christos "Protocol element ID %u in response from " MACSTR,
380 1.1 christos *pos, MAC2STR(sa));
381 1.1 christos return 0;
382 1.1 christos }
383 1.1 christos
384 1.1 christos adv_proto = pos;
385 1.1 christos pos += 2 + pos[1];
386 1.1 christos
387 1.1 christos /* Query Response Length */
388 1.1 christos if (pos + 2 > data + len) {
389 1.1 christos wpa_printf(MSG_DEBUG, "GAS: No room for GAS Response Length");
390 1.1 christos return 0;
391 1.1 christos }
392 1.1 christos resp_len = WPA_GET_LE16(pos);
393 1.1 christos pos += 2;
394 1.1 christos
395 1.1 christos if (pos + resp_len > data + len) {
396 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Truncated Query Response in "
397 1.1 christos "response from " MACSTR, MAC2STR(sa));
398 1.1 christos return 0;
399 1.1 christos }
400 1.1 christos
401 1.1 christos if (pos + resp_len < data + len) {
402 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Ignore %u octets of extra data "
403 1.1 christos "after Query Response from " MACSTR,
404 1.1 christos (unsigned int) (data + len - pos - resp_len),
405 1.1 christos MAC2STR(sa));
406 1.1 christos }
407 1.1 christos
408 1.1 christos if (action == WLAN_PA_GAS_COMEBACK_RESP)
409 1.1 christos gas_query_rx_comeback(gas, query, adv_proto, pos, resp_len,
410 1.1 christos frag_id, more_frags, comeback_delay);
411 1.1 christos else
412 1.1 christos gas_query_rx_initial(gas, query, adv_proto, pos, resp_len,
413 1.1 christos comeback_delay);
414 1.1 christos
415 1.1 christos return 0;
416 1.1 christos }
417 1.1 christos
418 1.1 christos
419 1.1 christos static void gas_query_timeout(void *eloop_data, void *user_ctx)
420 1.1 christos {
421 1.1 christos struct gas_query *gas = eloop_data;
422 1.1 christos struct gas_query_pending *query = user_ctx;
423 1.1 christos
424 1.1 christos wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR,
425 1.1 christos MAC2STR(query->addr));
426 1.1 christos gas_query_done(gas, query, GAS_QUERY_TIMEOUT);
427 1.1 christos }
428 1.1 christos
429 1.1 christos
430 1.1 christos static int gas_query_dialog_token_available(struct gas_query *gas,
431 1.1 christos const u8 *dst, u8 dialog_token)
432 1.1 christos {
433 1.1 christos struct gas_query_pending *q;
434 1.1 christos dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
435 1.1 christos if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 &&
436 1.1 christos dialog_token == q->dialog_token)
437 1.1 christos return 0;
438 1.1 christos }
439 1.1 christos
440 1.1 christos return 1;
441 1.1 christos }
442 1.1 christos
443 1.1 christos
444 1.1.1.2 christos /**
445 1.1.1.2 christos * gas_query_req - Request a GAS query
446 1.1.1.2 christos * @gas: GAS query data from gas_query_init()
447 1.1.1.2 christos * @dst: Destination MAC address for the query
448 1.1.1.2 christos * @freq: Frequency (in MHz) for the channel on which to send the query
449 1.1.1.2 christos * @req: GAS query payload
450 1.1.1.2 christos * @cb: Callback function for reporting GAS query result and response
451 1.1.1.2 christos * @ctx: Context pointer to use with the @cb call
452 1.1.1.2 christos * Returns: dialog token (>= 0) on success or -1 on failure
453 1.1.1.2 christos */
454 1.1 christos int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
455 1.1 christos struct wpabuf *req,
456 1.1 christos void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
457 1.1 christos enum gas_query_result result,
458 1.1 christos const struct wpabuf *adv_proto,
459 1.1 christos const struct wpabuf *resp, u16 status_code),
460 1.1 christos void *ctx)
461 1.1 christos {
462 1.1 christos struct gas_query_pending *query;
463 1.1 christos int dialog_token;
464 1.1 christos
465 1.1 christos if (wpabuf_len(req) < 3)
466 1.1 christos return -1;
467 1.1 christos
468 1.1 christos for (dialog_token = 0; dialog_token < 256; dialog_token++) {
469 1.1 christos if (gas_query_dialog_token_available(gas, dst, dialog_token))
470 1.1 christos break;
471 1.1 christos }
472 1.1 christos if (dialog_token == 256)
473 1.1 christos return -1; /* Too many pending queries */
474 1.1 christos
475 1.1 christos query = os_zalloc(sizeof(*query));
476 1.1 christos if (query == NULL)
477 1.1 christos return -1;
478 1.1 christos
479 1.1 christos os_memcpy(query->addr, dst, ETH_ALEN);
480 1.1 christos query->dialog_token = dialog_token;
481 1.1 christos query->freq = freq;
482 1.1 christos query->cb = cb;
483 1.1 christos query->ctx = ctx;
484 1.1 christos dl_list_add(&gas->pending, &query->list);
485 1.1 christos
486 1.1 christos *(wpabuf_mhead_u8(req) + 2) = dialog_token;
487 1.1 christos
488 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Starting request for " MACSTR
489 1.1 christos " dialog_token %u", MAC2STR(dst), dialog_token);
490 1.1 christos if (gas_query_tx(gas, query, req) < 0) {
491 1.1 christos wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
492 1.1 christos MACSTR, MAC2STR(query->addr));
493 1.1.1.2 christos dl_list_del(&query->list);
494 1.1 christos os_free(query);
495 1.1 christos return -1;
496 1.1 christos }
497 1.1 christos
498 1.1.1.2 christos eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout,
499 1.1 christos gas, query);
500 1.1 christos
501 1.1 christos return dialog_token;
502 1.1 christos }
503 1.1 christos
504 1.1 christos
505 1.1.1.2 christos /**
506 1.1.1.2 christos * gas_query_cancel - Cancel a pending GAS query
507 1.1.1.2 christos * @gas: GAS query data from gas_query_init()
508 1.1.1.2 christos * @dst: Destination MAC address for the query
509 1.1.1.2 christos * @dialog_token: Dialog token from gas_query_req()
510 1.1.1.2 christos */
511 1.1 christos void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token)
512 1.1 christos {
513 1.1 christos struct gas_query_pending *query;
514 1.1 christos
515 1.1 christos query = gas_query_get_pending(gas, dst, dialog_token);
516 1.1 christos if (query)
517 1.1 christos gas_query_done(gas, query, GAS_QUERY_CANCELLED);
518 1.1 christos
519 1.1 christos }
520