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