1 /*
2 * Generic advertisement service (GAS) server
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
4 * Copyright (c) 2020, The Linux Foundation
5 *
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
8 */
9
10 #include "includes.h"
11
12 #include "utils/common.h"
13 #include "utils/list.h"
14 #include "utils/eloop.h"
15 #include "ieee802_11_defs.h"
16 #include "gas.h"
17 #include "gas_server.h"
18
19
20 #define MAX_ADV_PROTO_ID_LEN 10
21 #define GAS_QUERY_TIMEOUT 10
22
23 struct gas_server_handler {
24 struct dl_list list;
25 u8 adv_proto_id[MAX_ADV_PROTO_ID_LEN];
26 u8 adv_proto_id_len;
27 struct wpabuf * (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
28 const u8 *query, size_t query_len,
29 u16 *comeback_delay);
30 void (*status_cb)(void *ctx, struct wpabuf *resp, int ok);
31 void *ctx;
32 struct gas_server *gas;
33 };
34
35 struct gas_server_response {
36 struct dl_list list;
37 size_t offset;
38 u8 frag_id;
39 struct wpabuf *resp;
40 int freq;
41 u8 dst[ETH_ALEN];
42 u8 dialog_token;
43 struct gas_server_handler *handler;
44 u16 comeback_delay;
45 };
46
47 struct gas_server {
48 struct dl_list handlers; /* struct gas_server_handler::list */
49 struct dl_list responses; /* struct gas_server_response::list */
50 void (*tx)(void *ctx, int freq, const u8 *da, struct wpabuf *resp,
51 unsigned int wait_time);
52 void *ctx;
53 };
54
55 static void gas_server_free_response(struct gas_server_response *response);
56
57
gas_server_response_timeout(void * eloop_ctx,void * user_ctx)58 static void gas_server_response_timeout(void *eloop_ctx, void *user_ctx)
59 {
60 struct gas_server_response *response = eloop_ctx;
61
62 wpa_printf(MSG_DEBUG, "GAS: Response @%p timeout for " MACSTR
63 " (dialog_token=%u freq=%d frag_id=%u sent=%lu/%lu) - drop pending data",
64 response, MAC2STR(response->dst), response->dialog_token,
65 response->freq, response->frag_id,
66 (unsigned long) response->offset,
67 (unsigned long) (response->resp ?
68 wpabuf_len(response->resp) : 0));
69 response->handler->status_cb(response->handler->ctx,
70 response->resp, 0);
71 response->resp = NULL;
72 dl_list_del(&response->list);
73 gas_server_free_response(response);
74 }
75
76
gas_server_free_response(struct gas_server_response * response)77 static void gas_server_free_response(struct gas_server_response *response)
78 {
79 if (!response)
80 return;
81 wpa_printf(MSG_DEBUG, "DPP: Free GAS response @%p", response);
82 eloop_cancel_timeout(gas_server_response_timeout, response, NULL);
83 wpabuf_free(response->resp);
84 os_free(response);
85 }
86
87
88 static void
gas_server_send_resp(struct gas_server * gas,struct gas_server_handler * handler,struct gas_server_response * response,const u8 * da,int freq,u8 dialog_token,struct wpabuf * query_resp,u16 comeback_delay)89 gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
90 struct gas_server_response *response,
91 const u8 *da, int freq, u8 dialog_token,
92 struct wpabuf *query_resp, u16 comeback_delay)
93 {
94 size_t max_len = (freq > 56160) ? 928 : 1400;
95 size_t hdr_len = 24 + 2 + 5 + 3 + handler->adv_proto_id_len + 2;
96 size_t resp_frag_len;
97 struct wpabuf *resp;
98
99 if (comeback_delay == 0 && !query_resp) {
100 gas_server_free_response(response);
101 return;
102 }
103
104 response->freq = freq;
105 response->handler = handler;
106 os_memcpy(response->dst, da, ETH_ALEN);
107 response->dialog_token = dialog_token;
108 if (comeback_delay) {
109 /* Need more time to prepare the response */
110 resp_frag_len = 0;
111 response->comeback_delay = comeback_delay;
112 } else if (hdr_len + wpabuf_len(query_resp) > max_len) {
113 /* Need to use comeback to initiate fragmentation */
114 comeback_delay = 1;
115 resp_frag_len = 0;
116 } else {
117 /* Full response fits into the initial response */
118 comeback_delay = 0;
119 resp_frag_len = wpabuf_len(query_resp);
120 }
121
122 resp = gas_build_initial_resp(dialog_token, WLAN_STATUS_SUCCESS,
123 comeback_delay,
124 handler->adv_proto_id_len +
125 resp_frag_len);
126 if (!resp) {
127 wpabuf_free(query_resp);
128 gas_server_free_response(response);
129 return;
130 }
131
132 /* Advertisement Protocol element */
133 wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO);
134 wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */
135 wpabuf_put_u8(resp, 0x7f);
136 /* Advertisement Protocol ID */
137 wpabuf_put_data(resp, handler->adv_proto_id, handler->adv_proto_id_len);
138
139 /* Query Response Length */
140 wpabuf_put_le16(resp, resp_frag_len);
141 if (!comeback_delay && query_resp)
142 wpabuf_put_buf(resp, query_resp);
143
144 if (comeback_delay && !query_resp) {
145 wpa_printf(MSG_DEBUG, "GAS: No response available yet");
146 } else if (comeback_delay) {
147 wpa_printf(MSG_DEBUG,
148 "GAS: Need to fragment query response");
149 } else {
150 wpa_printf(MSG_DEBUG,
151 "GAS: Full query response fits in the GAS Initial Response frame");
152 }
153 response->offset = resp_frag_len;
154 response->resp = query_resp;
155 dl_list_add(&gas->responses, &response->list);
156 gas->tx(gas->ctx, freq, da, resp, comeback_delay ? 2000 : 0);
157 wpabuf_free(resp);
158 eloop_register_timeout(GAS_QUERY_TIMEOUT, 0,
159 gas_server_response_timeout, response, NULL);
160 }
161
162
163 static int
gas_server_rx_initial_req(struct gas_server * gas,const u8 * da,const u8 * sa,const u8 * bssid,int freq,u8 dialog_token,const u8 * data,size_t len)164 gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
165 const u8 *bssid, int freq, u8 dialog_token,
166 const u8 *data, size_t len)
167 {
168 const u8 *pos, *end, *adv_proto, *query_req;
169 u8 adv_proto_len;
170 u16 query_req_len;
171 struct gas_server_handler *handler;
172 struct wpabuf *resp;
173 struct gas_server_response *response;
174
175 wpa_hexdump(MSG_MSGDUMP, "GAS: Received GAS Initial Request frame",
176 data, len);
177 pos = data;
178 end = data + len;
179
180 if (end - pos < 2 || pos[0] != WLAN_EID_ADV_PROTO) {
181 wpa_printf(MSG_DEBUG,
182 "GAS: No Advertisement Protocol element found");
183 return -1;
184 }
185 pos++;
186 adv_proto_len = *pos++;
187 if (end - pos < adv_proto_len || adv_proto_len < 2) {
188 wpa_printf(MSG_DEBUG,
189 "GAS: Truncated Advertisement Protocol element");
190 return -1;
191 }
192
193 adv_proto = pos;
194 pos += adv_proto_len;
195 wpa_hexdump(MSG_MSGDUMP, "GAS: Advertisement Protocol element",
196 adv_proto, adv_proto_len);
197
198 if (end - pos < 2) {
199 wpa_printf(MSG_DEBUG, "GAS: No Query Request Length field");
200 return -1;
201 }
202 query_req_len = WPA_GET_LE16(pos);
203 pos += 2;
204 if (end - pos < query_req_len) {
205 wpa_printf(MSG_DEBUG, "GAS: Truncated Query Request field");
206 return -1;
207 }
208 query_req = pos;
209 pos += query_req_len;
210 wpa_hexdump(MSG_MSGDUMP, "GAS: Query Request",
211 query_req, query_req_len);
212
213 if (pos < end) {
214 wpa_hexdump(MSG_MSGDUMP,
215 "GAS: Ignored extra data after Query Request field",
216 pos, end - pos);
217 }
218
219 response = os_zalloc(sizeof(*response));
220 if (!response)
221 return -1;
222
223 wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
224 dl_list_for_each(handler, &gas->handlers, struct gas_server_handler,
225 list) {
226 u16 comeback_delay = 0;
227
228 if (adv_proto_len < 1 + handler->adv_proto_id_len ||
229 os_memcmp(adv_proto + 1, handler->adv_proto_id,
230 handler->adv_proto_id_len) != 0)
231 continue;
232
233 wpa_printf(MSG_DEBUG,
234 "GAS: Calling handler for the requested Advertisement Protocol ID");
235 resp = handler->req_cb(handler->ctx, response, sa, query_req,
236 query_req_len, &comeback_delay);
237 wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler",
238 resp);
239 if (comeback_delay)
240 wpa_printf(MSG_DEBUG,
241 "GAS: Handler requested comeback delay: %u TU",
242 comeback_delay);
243 gas_server_send_resp(gas, handler, response, sa, freq,
244 dialog_token, resp, comeback_delay);
245 return 0;
246 }
247
248 wpa_printf(MSG_DEBUG,
249 "GAS: No registered handler for the requested Advertisement Protocol ID");
250 gas_server_free_response(response);
251 return -1;
252 }
253
254
255 static void
gas_server_handle_rx_comeback_req(struct gas_server_response * response)256 gas_server_handle_rx_comeback_req(struct gas_server_response *response)
257 {
258 struct gas_server_handler *handler = response->handler;
259 struct gas_server *gas = handler->gas;
260 size_t max_len = (response->freq > 56160) ? 928 : 1400;
261 size_t hdr_len = 24 + 2 + 6 + 3 + handler->adv_proto_id_len + 2;
262 size_t remaining, resp_frag_len;
263 struct wpabuf *resp;
264 unsigned int wait_time = 0;
265
266 if (!response->resp) {
267 resp = gas_build_comeback_resp(response->dialog_token,
268 WLAN_STATUS_SUCCESS, 0, 0,
269 response->comeback_delay,
270 handler->adv_proto_id_len);
271 if (!resp) {
272 dl_list_del(&response->list);
273 gas_server_free_response(response);
274 return;
275 }
276
277 /* Advertisement Protocol element */
278 wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO);
279 wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */
280 wpabuf_put_u8(resp, 0x7f);
281 /* Advertisement Protocol ID */
282 wpabuf_put_data(resp, handler->adv_proto_id,
283 handler->adv_proto_id_len);
284
285 /* Query Response Length */
286 wpabuf_put_le16(resp, 0);
287 goto send_resp;
288 }
289
290 remaining = wpabuf_len(response->resp) - response->offset;
291 if (hdr_len + remaining > max_len)
292 resp_frag_len = max_len - hdr_len;
293 else
294 resp_frag_len = remaining;
295 wpa_printf(MSG_DEBUG,
296 "GAS: Sending out %u/%u remaining Query Response octets",
297 (unsigned int) resp_frag_len, (unsigned int) remaining);
298
299 resp = gas_build_comeback_resp(response->dialog_token,
300 WLAN_STATUS_SUCCESS,
301 response->frag_id++,
302 resp_frag_len < remaining, 0,
303 handler->adv_proto_id_len +
304 resp_frag_len);
305 if (!resp) {
306 dl_list_del(&response->list);
307 gas_server_free_response(response);
308 return;
309 }
310
311 /* Advertisement Protocol element */
312 wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO);
313 wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */
314 wpabuf_put_u8(resp, 0x7f);
315 /* Advertisement Protocol ID */
316 wpabuf_put_data(resp, handler->adv_proto_id, handler->adv_proto_id_len);
317
318 /* Query Response Length */
319 wpabuf_put_le16(resp, resp_frag_len);
320 wpabuf_put_data(resp, wpabuf_head_u8(response->resp) + response->offset,
321 resp_frag_len);
322
323 response->offset += resp_frag_len;
324
325 if (remaining > resp_frag_len)
326 wait_time = 2000;
327
328 send_resp:
329 gas->tx(gas->ctx, response->freq, response->dst, resp, wait_time);
330 wpabuf_free(resp);
331 }
332
333
334 static int
gas_server_rx_comeback_req(struct gas_server * gas,const u8 * da,const u8 * sa,const u8 * bssid,int freq,u8 dialog_token)335 gas_server_rx_comeback_req(struct gas_server *gas, const u8 *da, const u8 *sa,
336 const u8 *bssid, int freq, u8 dialog_token)
337 {
338 struct gas_server_response *response;
339
340 dl_list_for_each(response, &gas->responses, struct gas_server_response,
341 list) {
342 if (response->dialog_token != dialog_token ||
343 os_memcmp(sa, response->dst, ETH_ALEN) != 0)
344 continue;
345 gas_server_handle_rx_comeback_req(response);
346 return 0;
347 }
348
349 wpa_printf(MSG_DEBUG, "GAS: No pending GAS response for " MACSTR
350 " (dialog token %u)", MAC2STR(sa), dialog_token);
351 return -1;
352 }
353
354
355 /**
356 * gas_query_rx - Indicate reception of a Public Action or Protected Dual frame
357 * @gas: GAS query data from gas_server_init()
358 * @da: Destination MAC address of the Action frame
359 * @sa: Source MAC address of the Action frame
360 * @bssid: BSSID of the Action frame
361 * @categ: Category of the Action frame
362 * @data: Payload of the Action frame
363 * @len: Length of @data
364 * @freq: Frequency (in MHz) on which the frame was received
365 * Returns: 0 if the Public Action frame was a GAS request frame or -1 if not
366 */
gas_server_rx(struct gas_server * gas,const u8 * da,const u8 * sa,const u8 * bssid,u8 categ,const u8 * data,size_t len,int freq)367 int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
368 const u8 *bssid, u8 categ, const u8 *data, size_t len,
369 int freq)
370 {
371 u8 action, dialog_token;
372 const u8 *pos, *end;
373
374 if (!gas || len < 2)
375 return -1;
376
377 if (categ == WLAN_ACTION_PROTECTED_DUAL)
378 return -1; /* Not supported for now */
379
380 pos = data;
381 end = data + len;
382 action = *pos++;
383 dialog_token = *pos++;
384
385 if (action != WLAN_PA_GAS_INITIAL_REQ &&
386 action != WLAN_PA_GAS_COMEBACK_REQ)
387 return -1; /* Not a GAS request */
388
389 wpa_printf(MSG_DEBUG, "GAS: Received GAS %s Request frame DA=" MACSTR
390 " SA=" MACSTR " BSSID=" MACSTR
391 " freq=%d dialog_token=%u len=%u",
392 action == WLAN_PA_GAS_INITIAL_REQ ? "Initial" : "Comeback",
393 MAC2STR(da), MAC2STR(sa), MAC2STR(bssid), freq, dialog_token,
394 (unsigned int) len);
395
396 if (action == WLAN_PA_GAS_INITIAL_REQ)
397 return gas_server_rx_initial_req(gas, da, sa, bssid,
398 freq, dialog_token,
399 pos, end - pos);
400 return gas_server_rx_comeback_req(gas, da, sa, bssid,
401 freq, dialog_token);
402 }
403
404
gas_server_handle_tx_status(struct gas_server_response * response,int ack)405 static void gas_server_handle_tx_status(struct gas_server_response *response,
406 int ack)
407 {
408 if (ack && response->resp &&
409 response->offset < wpabuf_len(response->resp)) {
410 wpa_printf(MSG_DEBUG,
411 "GAS: More fragments remaining - keep pending entry");
412 return;
413 }
414
415 if (ack && !response->resp && response->comeback_delay) {
416 wpa_printf(MSG_DEBUG,
417 "GAS: Waiting for response - keep pending entry");
418 return;
419 }
420
421 if (!ack)
422 wpa_printf(MSG_DEBUG,
423 "GAS: No ACK received - drop pending entry");
424 else
425 wpa_printf(MSG_DEBUG,
426 "GAS: Last fragment of the response sent out - drop pending entry");
427
428 response->handler->status_cb(response->handler->ctx,
429 response->resp, ack);
430 response->resp = NULL;
431 dl_list_del(&response->list);
432 gas_server_free_response(response);
433 }
434
435
gas_server_tx_status(struct gas_server * gas,const u8 * dst,const u8 * data,size_t data_len,int ack)436 void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
437 size_t data_len, int ack)
438 {
439 const u8 *pos;
440 u8 action, code, dialog_token;
441 struct gas_server_response *response;
442
443 if (data_len < 24 + 3)
444 return;
445 pos = data + 24;
446 action = *pos++;
447 code = *pos++;
448 dialog_token = *pos++;
449 if (action != WLAN_ACTION_PUBLIC ||
450 (code != WLAN_PA_GAS_INITIAL_RESP &&
451 code != WLAN_PA_GAS_COMEBACK_RESP))
452 return;
453 wpa_printf(MSG_DEBUG, "GAS: TX status dst=" MACSTR
454 " ack=%d %s dialog_token=%u",
455 MAC2STR(dst), ack,
456 code == WLAN_PA_GAS_INITIAL_RESP ? "initial" : "comeback",
457 dialog_token);
458 dl_list_for_each(response, &gas->responses, struct gas_server_response,
459 list) {
460 if (response->dialog_token != dialog_token ||
461 os_memcmp(dst, response->dst, ETH_ALEN) != 0)
462 continue;
463 gas_server_handle_tx_status(response, ack);
464 return;
465 }
466
467 wpa_printf(MSG_DEBUG, "GAS: No pending response matches TX status");
468 }
469
470
gas_server_set_resp(struct gas_server * gas,void * resp_ctx,struct wpabuf * resp)471 int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
472 struct wpabuf *resp)
473 {
474 struct gas_server_response *tmp, *response = NULL;
475
476 dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
477 list) {
478 if (tmp == resp_ctx) {
479 response = tmp;
480 break;
481 }
482 }
483
484 if (!response || response->resp)
485 return -1;
486
487 response->resp = resp;
488 return 0;
489 }
490
491
gas_server_response_sent(struct gas_server * gas,void * resp_ctx)492 bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx)
493 {
494 struct gas_server_response *tmp;
495
496 dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
497 list) {
498 if (tmp == resp_ctx)
499 return tmp->resp &&
500 tmp->offset == wpabuf_len(tmp->resp);
501 }
502
503 return false;
504 }
505
506
gas_server_init(void * ctx,void (* tx)(void * ctx,int freq,const u8 * da,struct wpabuf * buf,unsigned int wait_time))507 struct gas_server * gas_server_init(void *ctx,
508 void (*tx)(void *ctx, int freq,
509 const u8 *da,
510 struct wpabuf *buf,
511 unsigned int wait_time))
512 {
513 struct gas_server *gas;
514
515 gas = os_zalloc(sizeof(*gas));
516 if (!gas)
517 return NULL;
518 gas->ctx = ctx;
519 gas->tx = tx;
520 dl_list_init(&gas->handlers);
521 dl_list_init(&gas->responses);
522 return gas;
523 }
524
525
gas_server_deinit(struct gas_server * gas)526 void gas_server_deinit(struct gas_server *gas)
527 {
528 struct gas_server_handler *handler, *tmp;
529 struct gas_server_response *response, *tmp_r;
530
531 if (!gas)
532 return;
533
534 dl_list_for_each_safe(handler, tmp, &gas->handlers,
535 struct gas_server_handler, list) {
536 dl_list_del(&handler->list);
537 os_free(handler);
538 }
539
540 dl_list_for_each_safe(response, tmp_r, &gas->responses,
541 struct gas_server_response, list) {
542 dl_list_del(&response->list);
543 gas_server_free_response(response);
544 }
545
546 os_free(gas);
547 }
548
549
gas_server_register(struct gas_server * gas,const u8 * adv_proto_id,u8 adv_proto_id_len,struct wpabuf * (* req_cb)(void * ctx,void * resp_ctx,const u8 * sa,const u8 * query,size_t query_len,u16 * comeback_delay),void (* status_cb)(void * ctx,struct wpabuf * resp,int ok),void * ctx)550 int gas_server_register(struct gas_server *gas,
551 const u8 *adv_proto_id, u8 adv_proto_id_len,
552 struct wpabuf *
553 (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
554 const u8 *query, size_t query_len,
555 u16 *comeback_delay),
556 void (*status_cb)(void *ctx, struct wpabuf *resp,
557 int ok),
558 void *ctx)
559 {
560 struct gas_server_handler *handler;
561
562 if (!gas || adv_proto_id_len > MAX_ADV_PROTO_ID_LEN)
563 return -1;
564 handler = os_zalloc(sizeof(*handler));
565 if (!handler)
566 return -1;
567
568 os_memcpy(handler->adv_proto_id, adv_proto_id, adv_proto_id_len);
569 handler->adv_proto_id_len = adv_proto_id_len;
570 handler->req_cb = req_cb;
571 handler->status_cb = status_cb;
572 handler->ctx = ctx;
573 handler->gas = gas;
574 dl_list_add(&gas->handlers, &handler->list);
575
576 return 0;
577 }
578