1 /*
2 * Generic advertisement service (GAS) query
3 * Copyright (c) 2009, Atheros Communications
4 * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
5 * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi>
6 *
7 * This software may be distributed under the terms of the BSD license.
8 * See README for more details.
9 */
10
11 #include "includes.h"
12
13 #include "common.h"
14 #include "utils/eloop.h"
15 #include "common/ieee802_11_defs.h"
16 #include "common/gas.h"
17 #include "common/wpa_ctrl.h"
18 #include "rsn_supp/wpa.h"
19 #include "wpa_supplicant_i.h"
20 #include "config.h"
21 #include "driver_i.h"
22 #include "offchannel.h"
23 #include "gas_query.h"
24
25
26 /** GAS query timeout in seconds */
27 #define GAS_QUERY_TIMEOUT_PERIOD 2
28
29 /* GAS query wait-time / duration in ms */
30 #define GAS_QUERY_WAIT_TIME_INITIAL 1000
31 #define GAS_QUERY_WAIT_TIME_COMEBACK 150
32
33 #define GAS_QUERY_MAX_COMEBACK_DELAY 60000
34
35 /**
36 * struct gas_query_pending - Pending GAS query
37 */
38 struct gas_query_pending {
39 struct dl_list list;
40 struct gas_query *gas;
41 u8 addr[ETH_ALEN];
42 u8 dialog_token;
43 u8 next_frag_id;
44 unsigned int wait_comeback:1;
45 unsigned int offchannel_tx_started:1;
46 unsigned int retry:1;
47 unsigned int wildcard_bssid:1;
48 unsigned int maintain_addr:1;
49 int freq;
50 u16 status_code;
51 struct wpabuf *req;
52 struct wpabuf *adv_proto;
53 struct wpabuf *resp;
54 struct os_reltime last_oper;
55 void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
56 enum gas_query_result result,
57 const struct wpabuf *adv_proto,
58 const struct wpabuf *resp, u16 status_code);
59 void *ctx;
60 u8 sa[ETH_ALEN];
61 };
62
63 /**
64 * struct gas_query - Internal GAS query data
65 */
66 struct gas_query {
67 struct wpa_supplicant *wpa_s;
68 struct dl_list pending; /* struct gas_query_pending */
69 struct gas_query_pending *current;
70 struct wpa_radio_work *work;
71 struct os_reltime last_mac_addr_rand;
72 int last_rand_sa_type;
73 u8 rand_addr[ETH_ALEN];
74 };
75
76
77 static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
78 static void gas_query_timeout(void *eloop_data, void *user_ctx);
79 static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx);
80 static void gas_query_tx_initial_req(struct gas_query *gas,
81 struct gas_query_pending *query);
82 static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst);
83
84
ms_from_time(struct os_reltime * last)85 static int ms_from_time(struct os_reltime *last)
86 {
87 struct os_reltime now, res;
88
89 os_get_reltime(&now);
90 os_reltime_sub(&now, last, &res);
91 return res.sec * 1000 + res.usec / 1000;
92 }
93
94
95 /**
96 * gas_query_init - Initialize GAS query component
97 * @wpa_s: Pointer to wpa_supplicant data
98 * Returns: Pointer to GAS query data or %NULL on failure
99 */
gas_query_init(struct wpa_supplicant * wpa_s)100 struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s)
101 {
102 struct gas_query *gas;
103
104 gas = os_zalloc(sizeof(*gas));
105 if (gas == NULL)
106 return NULL;
107
108 gas->wpa_s = wpa_s;
109 dl_list_init(&gas->pending);
110
111 return gas;
112 }
113
114
gas_result_txt(enum gas_query_result result)115 static const char * gas_result_txt(enum gas_query_result result)
116 {
117 switch (result) {
118 case GAS_QUERY_SUCCESS:
119 return "SUCCESS";
120 case GAS_QUERY_FAILURE:
121 return "FAILURE";
122 case GAS_QUERY_TIMEOUT:
123 return "TIMEOUT";
124 case GAS_QUERY_PEER_ERROR:
125 return "PEER_ERROR";
126 case GAS_QUERY_INTERNAL_ERROR:
127 return "INTERNAL_ERROR";
128 case GAS_QUERY_STOPPED:
129 return "STOPPED";
130 case GAS_QUERY_DELETED_AT_DEINIT:
131 return "DELETED_AT_DEINIT";
132 }
133
134 return "N/A";
135 }
136
137
gas_query_free(struct gas_query_pending * query,int del_list)138 static void gas_query_free(struct gas_query_pending *query, int del_list)
139 {
140 struct gas_query *gas = query->gas;
141
142 if (del_list)
143 dl_list_del(&query->list);
144
145 if (gas->work && gas->work->ctx == query) {
146 radio_work_done(gas->work);
147 gas->work = NULL;
148 }
149
150 wpabuf_free(query->req);
151 wpabuf_free(query->adv_proto);
152 wpabuf_free(query->resp);
153 os_free(query);
154 }
155
156
gas_query_done(struct gas_query * gas,struct gas_query_pending * query,enum gas_query_result result)157 static void gas_query_done(struct gas_query *gas,
158 struct gas_query_pending *query,
159 enum gas_query_result result)
160 {
161 wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_DONE "addr=" MACSTR
162 " dialog_token=%u freq=%d status_code=%u result=%s",
163 MAC2STR(query->addr), query->dialog_token, query->freq,
164 query->status_code, gas_result_txt(result));
165 if (gas->current == query)
166 gas->current = NULL;
167 if (query->offchannel_tx_started)
168 offchannel_send_action_done(gas->wpa_s);
169 eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
170 eloop_cancel_timeout(gas_query_timeout, gas, query);
171 eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
172 dl_list_del(&query->list);
173 query->cb(query->ctx, query->addr, query->dialog_token, result,
174 query->adv_proto, query->resp, query->status_code);
175 gas_query_free(query, 0);
176 }
177
178
179 /**
180 * gas_query_deinit - Deinitialize GAS query component
181 * @gas: GAS query data from gas_query_init()
182 */
gas_query_deinit(struct gas_query * gas)183 void gas_query_deinit(struct gas_query *gas)
184 {
185 struct gas_query_pending *query, *next;
186
187 if (gas == NULL)
188 return;
189
190 dl_list_for_each_safe(query, next, &gas->pending,
191 struct gas_query_pending, list)
192 gas_query_done(gas, query, GAS_QUERY_DELETED_AT_DEINIT);
193
194 os_free(gas);
195 }
196
197
198 static struct gas_query_pending *
gas_query_get_pending(struct gas_query * gas,const u8 * addr,u8 dialog_token)199 gas_query_get_pending(struct gas_query *gas, const u8 *addr, u8 dialog_token)
200 {
201 struct gas_query_pending *q;
202 struct wpa_supplicant *wpa_s = gas->wpa_s;
203
204 dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
205 if (ether_addr_equal(q->addr, addr) &&
206 q->dialog_token == dialog_token)
207 return q;
208 if (wpa_s->valid_links &&
209 ether_addr_equal(wpa_s->ap_mld_addr, addr) &&
210 wpas_ap_link_address(wpa_s, q->addr))
211 return q;
212 }
213 return NULL;
214 }
215
216
gas_query_append(struct gas_query_pending * query,const u8 * data,size_t len)217 static int gas_query_append(struct gas_query_pending *query, const u8 *data,
218 size_t len)
219 {
220 if (wpabuf_resize(&query->resp, len) < 0) {
221 wpa_printf(MSG_DEBUG, "GAS: No memory to store the response");
222 return -1;
223 }
224 wpabuf_put_data(query->resp, data, len);
225 return 0;
226 }
227
228
gas_query_tx_status(struct wpa_supplicant * wpa_s,unsigned int freq,const u8 * dst,const u8 * src,const u8 * bssid,const u8 * data,size_t data_len,enum offchannel_send_action_result result)229 static void gas_query_tx_status(struct wpa_supplicant *wpa_s,
230 unsigned int freq, const u8 *dst,
231 const u8 *src, const u8 *bssid,
232 const u8 *data, size_t data_len,
233 enum offchannel_send_action_result result)
234 {
235 struct gas_query_pending *query;
236 struct gas_query *gas = wpa_s->gas;
237 int dur;
238
239 if (gas->current == NULL) {
240 wpa_printf(MSG_DEBUG, "GAS: Unexpected TX status: freq=%u dst="
241 MACSTR " result=%d - no query in progress",
242 freq, MAC2STR(dst), result);
243 return;
244 }
245
246 query = gas->current;
247
248 dur = ms_from_time(&query->last_oper);
249 wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR
250 " result=%d query=%p dialog_token=%u dur=%d ms",
251 freq, MAC2STR(dst), result, query, query->dialog_token, dur);
252 if (!ether_addr_equal(dst, query->addr)) {
253 wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination");
254 return;
255 }
256 os_get_reltime(&query->last_oper);
257
258 if (result == OFFCHANNEL_SEND_ACTION_SUCCESS ||
259 result == OFFCHANNEL_SEND_ACTION_NO_ACK) {
260 eloop_cancel_timeout(gas_query_timeout, gas, query);
261 if (result == OFFCHANNEL_SEND_ACTION_NO_ACK) {
262 wpa_printf(MSG_DEBUG, "GAS: No ACK to GAS request");
263 eloop_register_timeout(0, 250000,
264 gas_query_timeout, gas, query);
265 } else {
266 eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
267 gas_query_timeout, gas, query);
268 }
269 if (query->wait_comeback && !query->retry) {
270 eloop_cancel_timeout(gas_query_rx_comeback_timeout,
271 gas, query);
272 eloop_register_timeout(
273 0, (GAS_QUERY_WAIT_TIME_COMEBACK + 10) * 1000,
274 gas_query_rx_comeback_timeout, gas, query);
275 }
276 }
277 if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
278 eloop_cancel_timeout(gas_query_timeout, gas, query);
279 eloop_register_timeout(0, 0, gas_query_timeout, gas, query);
280 }
281 }
282
283
gas_query_tx(struct gas_query * gas,struct gas_query_pending * query,struct wpabuf * req,unsigned int wait_time)284 static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
285 struct wpabuf *req, unsigned int wait_time)
286 {
287 int res, prot = pmf_in_use(gas->wpa_s, query->addr);
288 const u8 *bssid;
289 const u8 wildcard_bssid[ETH_ALEN] = {
290 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
291 };
292
293 wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
294 "freq=%d prot=%d using src addr " MACSTR,
295 MAC2STR(query->addr), (unsigned int) wpabuf_len(req),
296 query->freq, prot, MAC2STR(query->sa));
297 if (prot) {
298 u8 *categ = wpabuf_mhead_u8(req);
299 *categ = WLAN_ACTION_PROTECTED_DUAL;
300 }
301 os_get_reltime(&query->last_oper);
302 if (gas->wpa_s->max_remain_on_chan &&
303 wait_time > gas->wpa_s->max_remain_on_chan)
304 wait_time = gas->wpa_s->max_remain_on_chan;
305 if (!query->wildcard_bssid &&
306 (!gas->wpa_s->conf->gas_address3 ||
307 (gas->wpa_s->current_ssid &&
308 gas->wpa_s->wpa_state >= WPA_ASSOCIATED &&
309 ether_addr_equal(query->addr, gas->wpa_s->bssid))))
310 bssid = query->addr;
311 else
312 bssid = wildcard_bssid;
313
314 res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
315 query->sa, bssid, wpabuf_head(req),
316 wpabuf_len(req), wait_time,
317 gas_query_tx_status, 0);
318
319 if (res == 0)
320 query->offchannel_tx_started = 1;
321 return res;
322 }
323
324
gas_query_tx_comeback_req(struct gas_query * gas,struct gas_query_pending * query)325 static void gas_query_tx_comeback_req(struct gas_query *gas,
326 struct gas_query_pending *query)
327 {
328 struct wpabuf *req;
329 unsigned int wait_time;
330
331 req = gas_build_comeback_req(query->dialog_token);
332 if (req == NULL) {
333 gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
334 return;
335 }
336
337 wait_time = (query->retry || !query->offchannel_tx_started) ?
338 GAS_QUERY_WAIT_TIME_INITIAL : GAS_QUERY_WAIT_TIME_COMEBACK;
339
340 if (gas_query_tx(gas, query, req, wait_time) < 0) {
341 wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
342 MACSTR, MAC2STR(query->addr));
343 gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
344 }
345
346 wpabuf_free(req);
347 }
348
349
gas_query_rx_comeback_timeout(void * eloop_data,void * user_ctx)350 static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx)
351 {
352 struct gas_query *gas = eloop_data;
353 struct gas_query_pending *query = user_ctx;
354 int dialog_token;
355
356 wpa_printf(MSG_DEBUG,
357 "GAS: No response to comeback request received (retry=%u)",
358 query->retry);
359 if (gas->current != query || query->retry)
360 return;
361 dialog_token = gas_query_new_dialog_token(gas, query->addr);
362 if (dialog_token < 0)
363 return;
364 wpa_printf(MSG_DEBUG,
365 "GAS: Retry GAS query due to comeback response timeout");
366 query->retry = 1;
367 query->dialog_token = dialog_token;
368 *(wpabuf_mhead_u8(query->req) + 2) = dialog_token;
369 query->wait_comeback = 0;
370 query->next_frag_id = 0;
371 wpabuf_free(query->adv_proto);
372 query->adv_proto = NULL;
373 eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
374 eloop_cancel_timeout(gas_query_timeout, gas, query);
375 gas_query_tx_initial_req(gas, query);
376 }
377
378
gas_query_tx_comeback_timeout(void * eloop_data,void * user_ctx)379 static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx)
380 {
381 struct gas_query *gas = eloop_data;
382 struct gas_query_pending *query = user_ctx;
383
384 wpa_printf(MSG_DEBUG, "GAS: Comeback timeout for request to " MACSTR,
385 MAC2STR(query->addr));
386 gas_query_tx_comeback_req(gas, query);
387 }
388
389
gas_query_tx_comeback_req_delay(struct gas_query * gas,struct gas_query_pending * query,u16 comeback_delay)390 static void gas_query_tx_comeback_req_delay(struct gas_query *gas,
391 struct gas_query_pending *query,
392 u16 comeback_delay)
393 {
394 unsigned int secs, usecs;
395
396 if (comeback_delay > 1 && query->offchannel_tx_started) {
397 offchannel_send_action_done(gas->wpa_s);
398 query->offchannel_tx_started = 0;
399 }
400
401 secs = (comeback_delay * 1024) / 1000000;
402 usecs = comeback_delay * 1024 - secs * 1000000;
403 wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR
404 " in %u secs %u usecs", MAC2STR(query->addr), secs, usecs);
405 eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
406 eloop_register_timeout(secs, usecs, gas_query_tx_comeback_timeout,
407 gas, query);
408 }
409
410
gas_query_rx_initial(struct gas_query * gas,struct gas_query_pending * query,const u8 * adv_proto,size_t adv_proto_len,const u8 * resp,size_t len,u16 comeback_delay)411 static void gas_query_rx_initial(struct gas_query *gas,
412 struct gas_query_pending *query,
413 const u8 *adv_proto, size_t adv_proto_len,
414 const u8 *resp, size_t len, u16 comeback_delay)
415 {
416 wpa_printf(MSG_DEBUG, "GAS: Received initial response from "
417 MACSTR " (dialog_token=%u comeback_delay=%u)",
418 MAC2STR(query->addr), query->dialog_token, comeback_delay);
419
420 query->adv_proto = wpabuf_alloc_copy(adv_proto, adv_proto_len);
421 if (query->adv_proto == NULL) {
422 gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
423 return;
424 }
425
426 if (comeback_delay) {
427 eloop_cancel_timeout(gas_query_timeout, gas, query);
428 query->wait_comeback = 1;
429 gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
430 return;
431 }
432
433 /* Query was completed without comeback mechanism */
434 if (gas_query_append(query, resp, len) < 0) {
435 gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
436 return;
437 }
438
439 gas_query_done(gas, query, GAS_QUERY_SUCCESS);
440 }
441
442
gas_query_rx_comeback(struct gas_query * gas,struct gas_query_pending * query,const u8 * adv_proto,size_t adv_proto_len,const u8 * resp,size_t len,u8 frag_id,u8 more_frags,u16 comeback_delay)443 static void gas_query_rx_comeback(struct gas_query *gas,
444 struct gas_query_pending *query,
445 const u8 *adv_proto, size_t adv_proto_len,
446 const u8 *resp, size_t len, u8 frag_id,
447 u8 more_frags, u16 comeback_delay)
448 {
449 wpa_printf(MSG_DEBUG, "GAS: Received comeback response from "
450 MACSTR " (dialog_token=%u frag_id=%u more_frags=%u "
451 "comeback_delay=%u)",
452 MAC2STR(query->addr), query->dialog_token, frag_id,
453 more_frags, comeback_delay);
454 eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
455
456 if (adv_proto_len != wpabuf_len(query->adv_proto) ||
457 os_memcmp(adv_proto, wpabuf_head(query->adv_proto),
458 wpabuf_len(query->adv_proto)) != 0) {
459 wpa_printf(MSG_DEBUG, "GAS: Advertisement Protocol changed "
460 "between initial and comeback response from "
461 MACSTR, MAC2STR(query->addr));
462 gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
463 return;
464 }
465
466 if (comeback_delay) {
467 if (frag_id) {
468 wpa_printf(MSG_DEBUG, "GAS: Invalid comeback response "
469 "with non-zero frag_id and comeback_delay "
470 "from " MACSTR, MAC2STR(query->addr));
471 gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
472 return;
473 }
474 gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
475 return;
476 }
477
478 if (frag_id != query->next_frag_id) {
479 wpa_printf(MSG_DEBUG, "GAS: Unexpected frag_id in response "
480 "from " MACSTR, MAC2STR(query->addr));
481 if (frag_id + 1 == query->next_frag_id) {
482 wpa_printf(MSG_DEBUG, "GAS: Drop frame as possible "
483 "retry of previous fragment");
484 return;
485 }
486 gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
487 return;
488 }
489 query->next_frag_id++;
490
491 if (gas_query_append(query, resp, len) < 0) {
492 gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
493 return;
494 }
495
496 if (more_frags) {
497 gas_query_tx_comeback_req(gas, query);
498 return;
499 }
500
501 gas_query_done(gas, query, GAS_QUERY_SUCCESS);
502 }
503
504
505 /**
506 * gas_query_rx - Indicate reception of a Public Action or Protected Dual frame
507 * @gas: GAS query data from gas_query_init()
508 * @da: Destination MAC address of the Action frame
509 * @sa: Source MAC address of the Action frame
510 * @bssid: BSSID of the Action frame
511 * @categ: Category of the Action frame
512 * @data: Payload of the Action frame
513 * @len: Length of @data
514 * @freq: Frequency (in MHz) on which the frame was received
515 * Returns: 0 if the Public Action frame was a GAS frame or -1 if not
516 */
gas_query_rx(struct gas_query * gas,const u8 * da,const u8 * sa,const u8 * bssid,u8 categ,const u8 * data,size_t len,int freq)517 int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
518 const u8 *bssid, u8 categ, const u8 *data, size_t len,
519 int freq)
520 {
521 struct gas_query_pending *query;
522 u8 action, dialog_token, frag_id = 0, more_frags = 0;
523 u16 comeback_delay, resp_len;
524 const u8 *pos, *adv_proto;
525 size_t adv_proto_len;
526 int prot, pmf;
527 unsigned int left;
528
529 if (gas == NULL || len < 4)
530 return -1;
531
532 pos = data;
533 action = *pos++;
534 dialog_token = *pos++;
535
536 if (action != WLAN_PA_GAS_INITIAL_RESP &&
537 action != WLAN_PA_GAS_COMEBACK_RESP)
538 return -1; /* Not a GAS response */
539
540 prot = categ == WLAN_ACTION_PROTECTED_DUAL;
541 pmf = pmf_in_use(gas->wpa_s, sa);
542 if (prot && !pmf) {
543 wpa_printf(MSG_DEBUG, "GAS: Drop unexpected protected GAS frame when PMF is disabled");
544 return 0;
545 }
546 if (!prot && pmf) {
547 wpa_printf(MSG_DEBUG, "GAS: Drop unexpected unprotected GAS frame when PMF is enabled");
548 return 0;
549 }
550
551 query = gas_query_get_pending(gas, sa, dialog_token);
552 if (query == NULL) {
553 wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR
554 " dialog token %u", MAC2STR(sa), dialog_token);
555 return -1;
556 }
557
558 wpa_printf(MSG_DEBUG, "GAS: Response in %d ms from " MACSTR,
559 ms_from_time(&query->last_oper), MAC2STR(sa));
560
561 if (query->wait_comeback && action == WLAN_PA_GAS_INITIAL_RESP) {
562 wpa_printf(MSG_DEBUG, "GAS: Unexpected initial response from "
563 MACSTR " dialog token %u when waiting for comeback "
564 "response", MAC2STR(sa), dialog_token);
565 return 0;
566 }
567
568 if (!query->wait_comeback && action == WLAN_PA_GAS_COMEBACK_RESP) {
569 wpa_printf(MSG_DEBUG, "GAS: Unexpected comeback response from "
570 MACSTR " dialog token %u when waiting for initial "
571 "response", MAC2STR(sa), dialog_token);
572 return 0;
573 }
574
575 query->status_code = WPA_GET_LE16(pos);
576 pos += 2;
577
578 if (query->status_code == WLAN_STATUS_QUERY_RESP_OUTSTANDING &&
579 action == WLAN_PA_GAS_COMEBACK_RESP) {
580 wpa_printf(MSG_DEBUG, "GAS: Allow non-zero status for outstanding comeback response");
581 } else if (query->status_code != WLAN_STATUS_SUCCESS) {
582 wpa_printf(MSG_DEBUG, "GAS: Query to " MACSTR " dialog token "
583 "%u failed - status code %u",
584 MAC2STR(sa), dialog_token, query->status_code);
585 gas_query_done(gas, query, GAS_QUERY_FAILURE);
586 return 0;
587 }
588
589 if (action == WLAN_PA_GAS_COMEBACK_RESP) {
590 if (pos + 1 > data + len)
591 return 0;
592 frag_id = *pos & 0x7f;
593 more_frags = (*pos & 0x80) >> 7;
594 pos++;
595 }
596
597 /* Comeback Delay */
598 if (pos + 2 > data + len)
599 return 0;
600 comeback_delay = WPA_GET_LE16(pos);
601 if (comeback_delay > GAS_QUERY_MAX_COMEBACK_DELAY)
602 comeback_delay = GAS_QUERY_MAX_COMEBACK_DELAY;
603 pos += 2;
604
605 /* Advertisement Protocol element */
606 adv_proto = pos;
607 left = data + len - adv_proto;
608 if (left < 2 || adv_proto[1] > left - 2) {
609 wpa_printf(MSG_DEBUG, "GAS: No room for Advertisement "
610 "Protocol element in the response from " MACSTR,
611 MAC2STR(sa));
612 return 0;
613 }
614
615 if (*adv_proto != WLAN_EID_ADV_PROTO) {
616 wpa_printf(MSG_DEBUG, "GAS: Unexpected Advertisement "
617 "Protocol element ID %u in response from " MACSTR,
618 *adv_proto, MAC2STR(sa));
619 return 0;
620 }
621 adv_proto_len = 2 + adv_proto[1];
622 if (adv_proto_len > (size_t) (data + len - pos))
623 return 0; /* unreachable due to an earlier check */
624
625 pos += adv_proto_len;
626
627 /* Query Response Length */
628 if (pos + 2 > data + len) {
629 wpa_printf(MSG_DEBUG, "GAS: No room for GAS Response Length");
630 return 0;
631 }
632 resp_len = WPA_GET_LE16(pos);
633 pos += 2;
634
635 left = data + len - pos;
636 if (resp_len > left) {
637 wpa_printf(MSG_DEBUG, "GAS: Truncated Query Response in "
638 "response from " MACSTR, MAC2STR(sa));
639 return 0;
640 }
641
642 if (resp_len < left) {
643 wpa_printf(MSG_DEBUG, "GAS: Ignore %u octets of extra data "
644 "after Query Response from " MACSTR,
645 left - resp_len, MAC2STR(sa));
646 }
647
648 if (action == WLAN_PA_GAS_COMEBACK_RESP)
649 gas_query_rx_comeback(gas, query, adv_proto, adv_proto_len,
650 pos, resp_len, frag_id, more_frags,
651 comeback_delay);
652 else
653 gas_query_rx_initial(gas, query, adv_proto, adv_proto_len,
654 pos, resp_len, comeback_delay);
655
656 return 0;
657 }
658
659
gas_query_timeout(void * eloop_data,void * user_ctx)660 static void gas_query_timeout(void *eloop_data, void *user_ctx)
661 {
662 struct gas_query *gas = eloop_data;
663 struct gas_query_pending *query = user_ctx;
664
665 wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR
666 " dialog token %u",
667 MAC2STR(query->addr), query->dialog_token);
668 gas_query_done(gas, query, GAS_QUERY_TIMEOUT);
669 }
670
671
gas_query_dialog_token_available(struct gas_query * gas,const u8 * dst,u8 dialog_token)672 static int gas_query_dialog_token_available(struct gas_query *gas,
673 const u8 *dst, u8 dialog_token)
674 {
675 struct gas_query_pending *q;
676 dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
677 if (ether_addr_equal(dst, q->addr) &&
678 dialog_token == q->dialog_token)
679 return 0;
680 }
681
682 return 1;
683 }
684
685
gas_query_start_cb(struct wpa_radio_work * work,int deinit)686 static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
687 {
688 struct gas_query_pending *query = work->ctx;
689 struct gas_query *gas = query->gas;
690 struct wpa_supplicant *wpa_s = gas->wpa_s;
691
692 if (deinit) {
693 if (work->started) {
694 gas->work = NULL;
695 gas_query_done(gas, query, GAS_QUERY_DELETED_AT_DEINIT);
696 return;
697 }
698
699 gas_query_free(query, 1);
700 return;
701 }
702
703 if (!query->maintain_addr && !wpa_s->conf->gas_rand_mac_addr) {
704 if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
705 wpa_msg(wpa_s, MSG_INFO,
706 "Failed to assign random MAC address for GAS");
707 gas_query_free(query, 1);
708 radio_work_done(work);
709 return;
710 }
711 os_memcpy(query->sa, wpa_s->own_addr, ETH_ALEN);
712 }
713
714 gas->work = work;
715 gas_query_tx_initial_req(gas, query);
716 }
717
718
gas_query_tx_initial_req(struct gas_query * gas,struct gas_query_pending * query)719 static void gas_query_tx_initial_req(struct gas_query *gas,
720 struct gas_query_pending *query)
721 {
722 if (gas_query_tx(gas, query, query->req,
723 GAS_QUERY_WAIT_TIME_INITIAL) < 0) {
724 wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
725 MACSTR, MAC2STR(query->addr));
726 gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
727 return;
728 }
729 gas->current = query;
730
731 wpa_printf(MSG_DEBUG, "GAS: Starting query timeout for dialog token %u",
732 query->dialog_token);
733 eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
734 gas_query_timeout, gas, query);
735 }
736
737
gas_query_new_dialog_token(struct gas_query * gas,const u8 * dst)738 static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst)
739 {
740 u8 dialog_token;
741 int i;
742
743 /* There should never be more than couple active GAS queries in
744 * progress, so it should be very likely to find an available dialog
745 * token by checking random values. Use a limit on the number of
746 * iterations to handle the unexpected case of large number of pending
747 * queries cleanly. */
748 for (i = 0; i < 256; i++) {
749 /* Get a random number and check if the slot is available */
750 if (os_get_random(&dialog_token, sizeof(dialog_token)) < 0)
751 break;
752 if (gas_query_dialog_token_available(gas, dst, dialog_token))
753 return dialog_token;
754 }
755
756 /* No dialog token value available */
757 return -1;
758 }
759
760
gas_query_set_sa(struct gas_query * gas,struct gas_query_pending * query)761 static int gas_query_set_sa(struct gas_query *gas,
762 struct gas_query_pending *query)
763 {
764 struct wpa_supplicant *wpa_s = gas->wpa_s;
765 struct os_reltime now;
766
767 if (query->maintain_addr ||
768 !wpa_s->conf->gas_rand_mac_addr ||
769 !(wpa_s->current_bss ?
770 (wpa_s->drv_flags &
771 WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED) :
772 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA))) {
773 /* Use own MAC address as the transmitter address */
774 wpa_printf(MSG_DEBUG,
775 "GAS: Use own MAC address as the transmitter address%s%s%s",
776 query->maintain_addr ? " (maintain_addr)" : "",
777 !wpa_s->conf->gas_rand_mac_addr ? " (no gas_rand_mac_adr set)" : "",
778 !(wpa_s->current_bss ?
779 (wpa_s->drv_flags &
780 WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED) :
781 (wpa_s->drv_flags &
782 WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA)) ?
783 " (no driver rand capa" : "");
784 os_memcpy(query->sa, wpa_s->own_addr, ETH_ALEN);
785 return 0;
786 }
787
788 os_get_reltime(&now);
789
790 if (wpa_s->conf->gas_rand_mac_addr == gas->last_rand_sa_type &&
791 gas->last_mac_addr_rand.sec != 0 &&
792 !os_reltime_expired(&now, &gas->last_mac_addr_rand,
793 wpa_s->conf->gas_rand_addr_lifetime)) {
794 wpa_printf(MSG_DEBUG,
795 "GAS: Use the previously selected random transmitter address "
796 MACSTR, MAC2STR(gas->rand_addr));
797 os_memcpy(query->sa, gas->rand_addr, ETH_ALEN);
798 return 0;
799 }
800
801 if (wpa_s->conf->gas_rand_mac_addr == 1 &&
802 random_mac_addr(gas->rand_addr) < 0) {
803 wpa_printf(MSG_ERROR, "GAS: Failed to get random address");
804 return -1;
805 }
806
807 if (wpa_s->conf->gas_rand_mac_addr == 2 &&
808 random_mac_addr_keep_oui(gas->rand_addr) < 0) {
809 wpa_printf(MSG_ERROR,
810 "GAS: Failed to get random address with same OUI");
811 return -1;
812 }
813
814 wpa_printf(MSG_DEBUG, "GAS: Use a new random transmitter address "
815 MACSTR, MAC2STR(gas->rand_addr));
816 os_memcpy(query->sa, gas->rand_addr, ETH_ALEN);
817 os_get_reltime(&gas->last_mac_addr_rand);
818 gas->last_rand_sa_type = wpa_s->conf->gas_rand_mac_addr;
819
820 return 0;
821 }
822
823
824 /**
825 * gas_query_req - Request a GAS query
826 * @gas: GAS query data from gas_query_init()
827 * @dst: Destination MAC address for the query
828 * @freq: Frequency (in MHz) for the channel on which to send the query
829 * @wildcard_bssid: Force use of wildcard BSSID value
830 * @maintain_addr: Maintain own MAC address for exchange (i.e., ignore MAC
831 * address randomization rules)
832 * @req: GAS query payload (to be freed by gas_query module in case of success
833 * return)
834 * @cb: Callback function for reporting GAS query result and response
835 * @ctx: Context pointer to use with the @cb call
836 * Returns: dialog token (>= 0) on success or -1 on failure
837 */
gas_query_req(struct gas_query * gas,const u8 * dst,int freq,int wildcard_bssid,int maintain_addr,struct wpabuf * req,void (* cb)(void * ctx,const u8 * dst,u8 dialog_token,enum gas_query_result result,const struct wpabuf * adv_proto,const struct wpabuf * resp,u16 status_code),void * ctx)838 int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
839 int wildcard_bssid, int maintain_addr, struct wpabuf *req,
840 void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
841 enum gas_query_result result,
842 const struct wpabuf *adv_proto,
843 const struct wpabuf *resp, u16 status_code),
844 void *ctx)
845 {
846 struct gas_query_pending *query;
847 int dialog_token;
848
849 if (wpabuf_len(req) < 3)
850 return -1;
851
852 dialog_token = gas_query_new_dialog_token(gas, dst);
853 if (dialog_token < 0)
854 return -1;
855
856 query = os_zalloc(sizeof(*query));
857 if (query == NULL)
858 return -1;
859
860 query->gas = gas;
861 query->maintain_addr = !!maintain_addr;
862 if (gas_query_set_sa(gas, query)) {
863 os_free(query);
864 return -1;
865 }
866 os_memcpy(query->addr, dst, ETH_ALEN);
867 query->dialog_token = dialog_token;
868 query->wildcard_bssid = !!wildcard_bssid;
869 query->freq = freq;
870 query->cb = cb;
871 query->ctx = ctx;
872 query->req = req;
873 dl_list_add(&gas->pending, &query->list);
874
875 *(wpabuf_mhead_u8(req) + 2) = dialog_token;
876
877 wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_START "addr=" MACSTR
878 " dialog_token=%u freq=%d",
879 MAC2STR(query->addr), query->dialog_token, query->freq);
880
881 if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb,
882 query) < 0) {
883 query->req = NULL; /* caller will free this in error case */
884 gas_query_free(query, 1);
885 return -1;
886 }
887
888 return dialog_token;
889 }
890
891
gas_query_stop(struct gas_query * gas,u8 dialog_token)892 int gas_query_stop(struct gas_query *gas, u8 dialog_token)
893 {
894 struct gas_query_pending *query;
895
896 dl_list_for_each(query, &gas->pending, struct gas_query_pending, list) {
897 if (query->dialog_token == dialog_token) {
898 if (!gas->work) {
899 /* The pending radio work has not yet been
900 * started, but the pending entry has a
901 * reference to the soon to be freed query.
902 * Need to remove that radio work now to avoid
903 * leaving behind a reference to freed memory.
904 */
905 radio_remove_pending_work(gas->wpa_s, query);
906 }
907 gas_query_done(gas, query, GAS_QUERY_STOPPED);
908 return 0;
909 }
910 }
911
912 return -1;
913 }
914