]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
GAS server: Asynchronous request handler comeback time indication
authorJouni Malinen <quic_jouni@quicinc.com>
Wed, 2 Feb 2022 14:48:51 +0000 (16:48 +0200)
committerJouni Malinen <j@w1.fi>
Wed, 2 Feb 2022 14:59:59 +0000 (16:59 +0200)
Extend the GAS server functionality to allow a request handler to return
the initial comeback delay with a later callback instead of having to
indicate the comeback delay when returning from the handler function.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
src/common/gas_server.c
src/common/gas_server.h
wpa_supplicant/dpp_supplicant.c

index 5f44ffebdea09d10fbb64f87b67a28ad9ac8b12c..3d5a27cf0d808b805eb39966bf8056dd1b12950d 100644 (file)
@@ -2,6 +2,7 @@
  * Generic advertisement service (GAS) server
  * Copyright (c) 2017, Qualcomm Atheros, Inc.
  * Copyright (c) 2020, The Linux Foundation
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -26,7 +27,7 @@ struct gas_server_handler {
        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);
+                                 int *comeback_delay);
        void (*status_cb)(void *ctx, struct wpabuf *resp, int ok);
        void *ctx;
        struct gas_server *gas;
@@ -42,6 +43,7 @@ struct gas_server_response {
        u8 dialog_token;
        struct gas_server_handler *handler;
        u16 comeback_delay;
+       bool initial_resp_sent;
 };
 
 struct gas_server {
@@ -86,25 +88,22 @@ static void gas_server_free_response(struct gas_server_response *response)
 
 
 static void
-gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
+gas_server_send_resp(struct gas_server *gas,
                     struct gas_server_response *response,
-                    const u8 *da, int freq, u8 dialog_token,
                     struct wpabuf *query_resp, u16 comeback_delay)
 {
-       size_t max_len = (freq > 56160) ? 928 : 1400;
+       struct gas_server_handler *handler = response->handler;
+       size_t max_len = (response->freq > 56160) ? 928 : 1400;
        size_t hdr_len = 24 + 2 + 5 + 3 + handler->adv_proto_id_len + 2;
        size_t resp_frag_len;
        struct wpabuf *resp;
 
        if (comeback_delay == 0 && !query_resp) {
+               dl_list_del(&response->list);
                gas_server_free_response(response);
                return;
        }
 
-       response->freq = freq;
-       response->handler = handler;
-       os_memcpy(response->dst, da, ETH_ALEN);
-       response->dialog_token = dialog_token;
        if (comeback_delay) {
                /* Need more time to prepare the response */
                resp_frag_len = 0;
@@ -119,12 +118,14 @@ gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
                resp_frag_len = wpabuf_len(query_resp);
        }
 
-       resp = gas_build_initial_resp(dialog_token, WLAN_STATUS_SUCCESS,
+       resp = gas_build_initial_resp(response->dialog_token,
+                                     WLAN_STATUS_SUCCESS,
                                      comeback_delay,
                                      handler->adv_proto_id_len +
                                      resp_frag_len);
        if (!resp) {
                wpabuf_free(query_resp);
+               dl_list_del(&response->list);
                gas_server_free_response(response);
                return;
        }
@@ -152,8 +153,9 @@ gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
        }
        response->offset = resp_frag_len;
        response->resp = query_resp;
-       dl_list_add(&gas->responses, &response->list);
-       gas->tx(gas->ctx, freq, da, resp, comeback_delay ? 2000 : 0);
+       response->initial_resp_sent = true;
+       gas->tx(gas->ctx, response->freq, response->dst, resp,
+               comeback_delay ? 2000 : 0);
        wpabuf_free(resp);
        eloop_register_timeout(GAS_QUERY_TIMEOUT, 0,
                               gas_server_response_timeout, response, NULL);
@@ -223,25 +225,35 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
        wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
        dl_list_for_each(handler, &gas->handlers, struct gas_server_handler,
                         list) {
-               u16 comeback_delay = 0;
+               int comeback_delay = 0;
 
                if (adv_proto_len < 1 + handler->adv_proto_id_len ||
                    os_memcmp(adv_proto + 1, handler->adv_proto_id,
                              handler->adv_proto_id_len) != 0)
                        continue;
 
+               response->freq = freq;
+               response->handler = handler;
+               os_memcpy(response->dst, sa, ETH_ALEN);
+               response->dialog_token = dialog_token;
+               dl_list_add(&gas->responses, &response->list);
+
                wpa_printf(MSG_DEBUG,
                           "GAS: Calling handler for the requested Advertisement Protocol ID");
                resp = handler->req_cb(handler->ctx, response, sa, query_req,
                                       query_req_len, &comeback_delay);
                wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler",
                                resp);
+               if (comeback_delay < 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "GAS: Handler requested short delay before sending out the initial response");
+                       return 0;
+               }
                if (comeback_delay)
                        wpa_printf(MSG_DEBUG,
                                   "GAS: Handler requested comeback delay: %u TU",
                                   comeback_delay);
-               gas_server_send_resp(gas, handler, response, sa, freq,
-                                    dialog_token, resp, comeback_delay);
+               gas_server_send_resp(gas, response, resp, comeback_delay);
                return 0;
        }
 
@@ -484,11 +496,42 @@ int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
        if (!response || response->resp)
                return -1;
 
+       if (!response->initial_resp_sent) {
+               wpa_printf(MSG_DEBUG, "GAS: Send the delayed initial response");
+               gas_server_send_resp(gas, response, resp, 0);
+               return 0;
+       }
+
        response->resp = resp;
        return 0;
 }
 
 
+int gas_server_set_comeback_delay(struct gas_server *gas, void *resp_ctx,
+                                 u16 comeback_delay)
+{
+       struct gas_server_response *tmp, *response = NULL;
+
+       dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
+                        list) {
+               if (tmp == resp_ctx) {
+                       response = tmp;
+                       break;
+               }
+       }
+
+       if (!response || response->initial_resp_sent)
+               return -1;
+
+       wpa_printf(MSG_DEBUG,
+                  "GAS: Send the delayed initial response with comeback delay %u",
+                  comeback_delay);
+       gas_server_send_resp(gas, response, NULL, comeback_delay);
+
+       return 0;
+}
+
+
 bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx)
 {
        struct gas_server_response *tmp;
@@ -552,7 +595,7 @@ int gas_server_register(struct gas_server *gas,
                        struct wpabuf *
                        (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
                                  const u8 *query, size_t query_len,
-                                 u16 *comeback_delay),
+                                 int *comeback_delay),
                        void (*status_cb)(void *ctx, struct wpabuf *resp,
                                          int ok),
                        void *ctx)
index db00f87e8de1097fe0a31925a381afd9b586b723..8d5eaa256bac29fbddc4718431f3a5f2cfbad0aa 100644 (file)
@@ -2,6 +2,7 @@
  * Generic advertisement service (GAS) server
  * Copyright (c) 2017, Qualcomm Atheros, Inc.
  * Copyright (c) 2020, The Linux Foundation
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -25,7 +26,7 @@ int gas_server_register(struct gas_server *gas,
                        struct wpabuf *
                        (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
                                  const u8 *query, size_t query_len,
-                                 u16 *comeback_delay),
+                                 int *comeback_delay),
                        void (*status_cb)(void *ctx, struct wpabuf *resp,
                                          int ok),
                        void *ctx);
@@ -34,6 +35,8 @@ int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
                  int freq);
 void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
                          size_t data_len, int ack);
+int gas_server_set_comeback_delay(struct gas_server *gas, void *resp_ctx,
+                                 u16 comeback_delay);
 int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
                        struct wpabuf *resp);
 bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx);
index acd8521c36e79e82c47f153de0a7c9b77e11f37c..3189b173c93e0ee173c39c63aaf32f3cf993db1b 100644 (file)
@@ -3142,7 +3142,7 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
 
 static struct wpabuf *
 wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa,
-                        const u8 *query, size_t query_len, u16 *comeback_delay)
+                        const u8 *query, size_t query_len, int *comeback_delay)
 {
        struct wpa_supplicant *wpa_s = ctx;
        struct dpp_authentication *auth = wpa_s->dpp_auth;