[PATCH 1/4] gas_server: resend a response fragment after a lost ACK
Gustavo Bertoli
gubertoli at gmail.com
Tue Jun 23 08:57:14 PDT 2026
A fragmented GAS response advances its cursor as each fragment is handed to
the driver, regardless of whether that fragment was ACKed. On a
remain-on-channel rendezvous a fragment can be lost to dwell misalignment
after the cursor has moved past it, so it was never resent and the transfer
stalled. Track the previous offset and a tx_pending flag, and on a no-ACK TX
status roll back and resend that fragment on the next Comeback Request.
A Comeback Request that arrives before the previous fragment's TX status has
resolved is not yet known to be missed; resending then would supersede the
still in-flight frame and discard its TX status. Wait for the status
instead.
Signed-off-by: Gustavo Bertoli <gubertoli at gmail.com>
---
src/common/gas_server.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/src/common/gas_server.c b/src/common/gas_server.c
index 52c14df36..80c75251a 100644
--- a/src/common/gas_server.c
+++ b/src/common/gas_server.c
@@ -36,7 +36,9 @@ struct gas_server_handler {
struct gas_server_response {
struct dl_list list;
size_t offset;
+ size_t last_offset;
u8 frag_id;
+ bool tx_pending;
struct wpabuf *resp;
int freq;
u8 dst[ETH_ALEN];
@@ -275,6 +277,11 @@ gas_server_handle_rx_comeback_req(struct gas_server_response *response)
struct wpabuf *resp;
unsigned int wait_time = 0;
+ if (response->tx_pending && response->resp) {
+ /* Previous fragment's TX status still pending; wait for it */
+ return;
+ }
+
if (!response->resp) {
resp = gas_build_comeback_resp(response->dialog_token,
WLAN_STATUS_SUCCESS, 0, 0,
@@ -332,6 +339,7 @@ gas_server_handle_rx_comeback_req(struct gas_server_response *response)
wpabuf_put_data(resp, wpabuf_head_u8(response->resp) + response->offset,
resp_frag_len);
+ response->last_offset = response->offset;
response->offset += resp_frag_len;
if (remaining > resp_frag_len)
@@ -339,6 +347,7 @@ gas_server_handle_rx_comeback_req(struct gas_server_response *response)
send_resp:
gas->tx(gas->ctx, response->freq, response->dst, resp, wait_time);
+ response->tx_pending = true;
wpabuf_free(resp);
}
@@ -417,6 +426,8 @@ int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
static void gas_server_handle_tx_status(struct gas_server_response *response,
int ack)
{
+ response->tx_pending = false;
+
if (ack && response->resp &&
response->offset < wpabuf_len(response->resp)) {
wpa_printf(MSG_DEBUG,
@@ -430,6 +441,15 @@ static void gas_server_handle_tx_status(struct gas_server_response *response,
return;
}
+ if (!ack && response->resp) {
+ /* Fragment not ACKed; roll back to resend on the next request */
+ if (response->frag_id > 0) {
+ response->offset = response->last_offset;
+ response->frag_id--;
+ }
+ return;
+ }
+
if (!ack)
wpa_printf(MSG_DEBUG,
"GAS: No ACK received - drop pending entry");
--
2.39.5
More information about the Hostap
mailing list