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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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