[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