]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211: Cancel all pending TX frame cookies
authorJouni Malinen <jouni@qca.qualcomm.com>
Tue, 1 Dec 2015 22:12:32 +0000 (00:12 +0200)
committerJouni Malinen <j@w1.fi>
Wed, 2 Dec 2015 10:37:10 +0000 (12:37 +0200)
These needs to be cancelled so that the kernel driver does not get left
with all old entries blocking other offchannel operations.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211.h

index 0fa2c7ea8a6a7c05363ea85b73eaf9f96b0a17ae..0fd836ba67c36ca6a04905ab28574275a39c4864 100644 (file)
@@ -6183,6 +6183,20 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
 
                if (cookie_out)
                        *cookie_out = no_ack ? (u64) -1 : cookie;
+
+               if (drv->num_send_action_cookies == MAX_SEND_ACTION_COOKIES) {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Drop oldest pending send action cookie 0x%llx",
+                                  (long long unsigned int)
+                                  drv->send_action_cookies[0]);
+                       os_memmove(&drv->send_action_cookies[0],
+                                  &drv->send_action_cookies[1],
+                                  (MAX_SEND_ACTION_COOKIES - 1) *
+                                  sizeof(u64));
+                       drv->num_send_action_cookies--;
+               }
+               drv->send_action_cookies[drv->num_send_action_cookies] = cookie;
+               drv->num_send_action_cookies++;
        }
 
 fail:
@@ -6237,17 +6251,16 @@ static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
 }
 
 
-static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
+static void nl80211_frame_wait_cancel(struct i802_bss *bss, u64 cookie)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret;
 
        wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx",
-                  (long long unsigned int) drv->send_action_cookie);
+                  (long long unsigned int) cookie);
        if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME_WAIT_CANCEL)) ||
-           nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie)) {
+           nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) {
                nlmsg_free(msg);
                return;
        }
@@ -6259,6 +6272,30 @@ static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
 }
 
 
+static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       unsigned int i;
+       u64 cookie;
+
+       /* Cancel the last pending TX cookie */
+       nl80211_frame_wait_cancel(bss, drv->send_action_cookie);
+
+       /*
+        * Cancel the other pending TX cookies, if any. This is needed since
+        * the driver may keep a list of all pending offchannel TX operations
+        * and free up the radio only once they have expired or cancelled.
+        */
+       for (i = drv->num_send_action_cookies; i > 0; i--) {
+               cookie = drv->send_action_cookies[i - 1];
+               if (cookie != drv->send_action_cookie)
+                       nl80211_frame_wait_cancel(bss, cookie);
+       }
+       drv->num_send_action_cookies = 0;
+}
+
+
 static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
                                                unsigned int duration)
 {
index f042c3c9fe9203258ad085c1dd24e49f332c1fc1..21c0b6db906d7eeb7bf76efd33af72bc1fdad1a3 100644 (file)
@@ -153,6 +153,9 @@ struct wpa_driver_nl80211_data {
        u64 vendor_scan_cookie;
        u64 remain_on_chan_cookie;
        u64 send_action_cookie;
+#define MAX_SEND_ACTION_COOKIES 20
+       u64 send_action_cookies[MAX_SEND_ACTION_COOKIES];
+       unsigned int num_send_action_cookies;
 
        unsigned int last_mgmt_freq;