From da65e713602d7c27015f661d3091d659ff216b22 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 4 Feb 2022 00:12:13 +0200 Subject: [PATCH] nl80211: Add a handler for NL80211_CMD_FRAME_WAIT_CANCEL events This can be helpful in figuring out when the driver has stopped waiting on a specific channel and would need a remain-on-channel command to continue listening on that channel. Signed-off-by: Jouni Malinen --- src/drivers/driver.h | 9 ++++++++ src/drivers/driver_common.c | 1 + src/drivers/driver_nl80211_event.c | 37 ++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index d3312a34d..85be4c384 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -5129,6 +5129,15 @@ enum wpa_event_type { * is required to provide more details of the frame. */ EVENT_UNPROT_BEACON, + + /** + * EVENT_TX_WAIT_EXPIRE - TX wait timed out + * + * This event is used to indicate when the driver has completed + * wait for a response frame based on a TX request that specified a + * non-zero wait time and that has not been explicitly cancelled. + */ + EVENT_TX_WAIT_EXPIRE, }; diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index 1cb976011..741521c67 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -90,6 +90,7 @@ const char * event_to_string(enum wpa_event_type event) E2S(WDS_STA_INTERFACE_STATUS); E2S(UPDATE_DH); E2S(UNPROT_BEACON); + E2S(TX_WAIT_EXPIRE); } return "UNKNOWN"; diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 0f0a01d01..fd2146793 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -2855,6 +2855,40 @@ nl80211_control_port_frame_tx_status(struct wpa_driver_nl80211_data *drv, } +static void nl80211_frame_wait_cancel(struct wpa_driver_nl80211_data *drv, + struct nlattr *cookie_attr) +{ + unsigned int i; + u64 cookie; + bool match = false; + + if (!cookie_attr) + return; + cookie = nla_get_u64(cookie_attr); + + for (i = 0; i < drv->num_send_frame_cookies; i++) { + if (cookie == drv->send_frame_cookies[i]) { + match = true; + break; + } + } + wpa_printf(MSG_DEBUG, + "nl80211: TX frame wait expired for cookie 0x%llx%s", + (long long unsigned int) cookie, + match ? " (match)" : ""); + if (!match) + return; + + if (i < drv->num_send_frame_cookies - 1) + os_memmove(&drv->send_frame_cookies[i], + &drv->send_frame_cookies[i + 1], + (drv->num_send_frame_cookies - i - 1) * sizeof(u64)); + drv->num_send_frame_cookies--; + + wpa_supplicant_event(drv->ctx, EVENT_TX_WAIT_EXPIRE, NULL); +} + + static void do_process_drv_event(struct i802_bss *bss, int cmd, struct nlattr **tb) { @@ -3101,6 +3135,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, tb[NL80211_ATTR_ACK], tb[NL80211_ATTR_COOKIE]); break; + case NL80211_CMD_FRAME_WAIT_CANCEL: + nl80211_frame_wait_cancel(drv, tb[NL80211_ATTR_COOKIE]); + break; default: wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event " "(cmd=%d)", cmd);