cfg80211: report userspace SME connected event properly
[pandora-kernel.git] / net / wireless / mlme.c
index 1a92bf7..79d2eec 100644 (file)
@@ -8,11 +8,13 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/nl80211.h>
+#include <linux/wireless.h>
 #include <net/cfg80211.h>
+#include <net/iw_handler.h>
 #include "core.h"
 #include "nl80211.h"
 
-void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp)
+void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
@@ -23,6 +25,8 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gf
        u16 status = le16_to_cpu(mgmt->u.auth.status_code);
        bool done = false;
 
+       wdev_lock(wdev);
+
        for (i = 0; i < MAX_AUTH_BSSES; i++) {
                if (wdev->authtry_bsses[i] &&
                    memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid,
@@ -41,12 +45,14 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gf
 
        WARN_ON(!done);
 
-       nl80211_send_rx_auth(rdev, dev, buf, len, gfp);
+       nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
        cfg80211_sme_rx_auth(dev, buf, len);
+
+       wdev_unlock(wdev);
 }
 EXPORT_SYMBOL(cfg80211_send_rx_auth);
 
-void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp)
+void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
 {
        u16 status_code;
        struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -55,32 +61,68 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, g
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
        u8 *ie = mgmt->u.assoc_resp.variable;
        int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
-       bool done;
+       struct cfg80211_internal_bss *bss = NULL;
+
+       wdev_lock(wdev);
 
        status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
 
-       nl80211_send_rx_assoc(rdev, dev, buf, len, gfp);
+       /*
+        * This is a bit of a hack, we don't notify userspace of
+        * a (re-)association reply if we tried to send a reassoc
+        * and got a reject -- we only try again with an assoc
+        * frame instead of reassoc.
+        */
+       if (status_code != WLAN_STATUS_SUCCESS && wdev->conn &&
+           cfg80211_sme_failed_reassoc(wdev))
+               goto out;
 
-       cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
-                               status_code, gfp);
+       nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
 
        if (status_code == WLAN_STATUS_SUCCESS) {
-               for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) {
-                       if (wdev->auth_bsses[i] == wdev->current_bss) {
-                               cfg80211_unhold_bss(wdev->auth_bsses[i]);
-                               cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
+               for (i = 0; i < MAX_AUTH_BSSES; i++) {
+                       if (!wdev->auth_bsses[i])
+                               continue;
+                       if (memcmp(wdev->auth_bsses[i]->pub.bssid, mgmt->bssid,
+                                  ETH_ALEN) == 0) {
+                               bss = wdev->auth_bsses[i];
                                wdev->auth_bsses[i] = NULL;
-                               done = true;
+                               /* additional reference to drop hold */
+                               cfg80211_ref_bss(bss);
                                break;
                        }
                }
 
-               WARN_ON(!done);
+               WARN_ON(!bss);
+       }
+
+       if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) {
+               /*
+                * This is for the userspace SME, the CONNECTING
+                * state will be changed to CONNECTED by
+                * __cfg80211_connect_result() below.
+                */
+               wdev->sme_state = CFG80211_SME_CONNECTING;
        }
+
+       /* this consumes one bss reference (unless bss is NULL) */
+       __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
+                                 status_code,
+                                 status_code == WLAN_STATUS_SUCCESS,
+                                 bss ? &bss->pub : NULL);
+       /* drop hold now, and also reference acquired above */
+       if (bss) {
+               cfg80211_unhold_bss(bss);
+               cfg80211_put_bss(&bss->pub);
+       }
+
+ out:
+       wdev_unlock(wdev);
 }
 EXPORT_SYMBOL(cfg80211_send_rx_assoc);
 
-void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp)
+static void __cfg80211_send_deauth(struct net_device *dev,
+                                  const u8 *buf, size_t len)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
@@ -90,7 +132,9 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp
        int i;
        bool done = false;
 
-       nl80211_send_deauth(rdev, dev, buf, len, gfp);
+       ASSERT_WDEV_LOCK(wdev);
+
+       nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
 
        if (wdev->current_bss &&
            memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
@@ -116,32 +160,45 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp
                        break;
                }
        }
-/*
- * mac80211 currently triggers this warning,
- * so disable for now (it's harmless, just
- * means that we got a spurious event)
 
        WARN_ON(!done);
 
- */
-
        if (wdev->sme_state == CFG80211_SME_CONNECTED) {
                u16 reason_code;
                bool from_ap;
 
                reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
-               from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
-               __cfg80211_disconnected(dev, gfp, NULL, 0,
-                                       reason_code, from_ap);
+               from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
+               __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
        } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
-               cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
-                                       WLAN_STATUS_UNSPECIFIED_FAILURE, gfp);
+               __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
+                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                         false, NULL);
+       }
+}
+
+
+void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
+                         void *cookie)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       BUG_ON(cookie && wdev != cookie);
+
+       if (cookie) {
+               /* called within callback */
+               __cfg80211_send_deauth(dev, buf, len);
+       } else {
+               wdev_lock(wdev);
+               __cfg80211_send_deauth(dev, buf, len);
+               wdev_unlock(wdev);
        }
 }
 EXPORT_SYMBOL(cfg80211_send_deauth);
 
-void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp)
+static void __cfg80211_send_disassoc(struct net_device *dev,
+                                    const u8 *buf, size_t len)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
@@ -153,13 +210,15 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, g
        bool from_ap;
        bool done = false;
 
-       nl80211_send_disassoc(rdev, dev, buf, len, gfp);
+       ASSERT_WDEV_LOCK(wdev);
+
+       nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
 
-       if (!wdev->sme_state == CFG80211_SME_CONNECTED)
+       if (wdev->sme_state != CFG80211_SME_CONNECTED)
                return;
 
        if (wdev->current_bss &&
-           memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) {
+           memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
                for (i = 0; i < MAX_AUTH_BSSES; i++) {
                        if (wdev->authtry_bsses[i] || wdev->auth_bsses[i])
                                continue;
@@ -176,13 +235,29 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, g
 
        reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
-       from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
-       __cfg80211_disconnected(dev, gfp, NULL, 0,
-                               reason_code, from_ap);
+       from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
+       __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
+}
+
+void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len,
+                           void *cookie)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       BUG_ON(cookie && wdev != cookie);
+
+       if (cookie) {
+               /* called within callback */
+               __cfg80211_send_disassoc(dev, buf, len);
+       } else {
+               wdev_lock(wdev);
+               __cfg80211_send_disassoc(dev, buf, len);
+               wdev_unlock(wdev);
+       }
 }
 EXPORT_SYMBOL(cfg80211_send_disassoc);
 
-void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp)
+void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
@@ -190,10 +265,13 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gf
        int i;
        bool done = false;
 
-       nl80211_send_auth_timeout(rdev, dev, addr, gfp);
+       wdev_lock(wdev);
+
+       nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
        if (wdev->sme_state == CFG80211_SME_CONNECTING)
-               cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
-                                       WLAN_STATUS_UNSPECIFIED_FAILURE, gfp);
+               __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
+                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                         false, NULL);
 
        for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
                if (wdev->authtry_bsses[i] &&
@@ -208,10 +286,12 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gf
        }
 
        WARN_ON(!done);
+
+       wdev_unlock(wdev);
 }
 EXPORT_SYMBOL(cfg80211_send_auth_timeout);
 
-void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp)
+void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
@@ -219,10 +299,13 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t g
        int i;
        bool done = false;
 
-       nl80211_send_assoc_timeout(rdev, dev, addr, gfp);
+       wdev_lock(wdev);
+
+       nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
        if (wdev->sme_state == CFG80211_SME_CONNECTING)
-               cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
-                                       WLAN_STATUS_UNSPECIFIED_FAILURE, gfp);
+               __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
+                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                         false, NULL);
 
        for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
                if (wdev->auth_bsses[i] &&
@@ -237,6 +320,8 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t g
        }
 
        WARN_ON(!done);
+
+       wdev_unlock(wdev);
 }
 EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
 
@@ -267,17 +352,41 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
 EXPORT_SYMBOL(cfg80211_michael_mic_failure);
 
 /* some MLME handling for userspace SME */
-int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
-                      struct net_device *dev, struct ieee80211_channel *chan,
-                      enum nl80211_auth_type auth_type, const u8 *bssid,
-                      const u8 *ssid, int ssid_len,
-                      const u8 *ie, int ie_len)
+int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
+                        struct net_device *dev,
+                        struct ieee80211_channel *chan,
+                        enum nl80211_auth_type auth_type,
+                        const u8 *bssid,
+                        const u8 *ssid, int ssid_len,
+                        const u8 *ie, int ie_len,
+                        const u8 *key, int key_len, int key_idx)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_auth_request req;
        struct cfg80211_internal_bss *bss;
        int i, err, slot = -1, nfree = 0;
 
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+               if (!key || !key_len || key_idx < 0 || key_idx > 4)
+                       return -EINVAL;
+
+       if (wdev->current_bss &&
+           memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
+               return -EALREADY;
+
+       for (i = 0; i < MAX_AUTH_BSSES; i++) {
+               if (wdev->authtry_bsses[i] &&
+                   memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid,
+                                               ETH_ALEN) == 0)
+                       return -EALREADY;
+               if (wdev->auth_bsses[i] &&
+                   memcmp(bssid, wdev->auth_bsses[i]->pub.bssid,
+                                               ETH_ALEN) == 0)
+                       return -EALREADY;
+       }
+
        memset(&req, 0, sizeof(req));
 
        req.ie = ie;
@@ -285,18 +394,14 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
        req.auth_type = auth_type;
        req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
                                   WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+       req.key = key;
+       req.key_len = key_len;
+       req.key_idx = key_idx;
        if (!req.bss)
                return -ENOENT;
 
        bss = bss_from_pub(req.bss);
 
-       for (i = 0; i < MAX_AUTH_BSSES; i++) {
-               if (bss == wdev->auth_bsses[i]) {
-                       err = -EALREADY;
-                       goto out;
-               }
-       }
-
        for (i = 0; i < MAX_AUTH_BSSES; i++) {
                if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
                        slot = i;
@@ -325,17 +430,39 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
        return err;
 }
 
-int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
-                       struct net_device *dev, struct ieee80211_channel *chan,
-                       const u8 *bssid, const u8 *ssid, int ssid_len,
-                       const u8 *ie, int ie_len, bool use_mfp,
-                       struct cfg80211_crypto_settings *crypt)
+int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
+                      struct net_device *dev, struct ieee80211_channel *chan,
+                      enum nl80211_auth_type auth_type, const u8 *bssid,
+                      const u8 *ssid, int ssid_len,
+                      const u8 *ie, int ie_len,
+                      const u8 *key, int key_len, int key_idx)
+{
+       int err;
+
+       wdev_lock(dev->ieee80211_ptr);
+       err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
+                                  ssid, ssid_len, ie, ie_len,
+                                  key, key_len, key_idx);
+       wdev_unlock(dev->ieee80211_ptr);
+
+       return err;
+}
+
+int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
+                         struct net_device *dev,
+                         struct ieee80211_channel *chan,
+                         const u8 *bssid, const u8 *prev_bssid,
+                         const u8 *ssid, int ssid_len,
+                         const u8 *ie, int ie_len, bool use_mfp,
+                         struct cfg80211_crypto_settings *crypt)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_assoc_request req;
        struct cfg80211_internal_bss *bss;
        int i, err, slot = -1;
 
+       ASSERT_WDEV_LOCK(wdev);
+
        memset(&req, 0, sizeof(req));
 
        if (wdev->current_bss)
@@ -345,6 +472,7 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
        req.ie_len = ie_len;
        memcpy(&req.crypto, crypt, sizeof(req.crypto));
        req.use_mfp = use_mfp;
+       req.prev_bssid = prev_bssid;
        req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
                                   WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
        if (!req.bss)
@@ -371,14 +499,35 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
        return err;
 }
 
-int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
-                        struct net_device *dev, const u8 *bssid,
-                        const u8 *ie, int ie_len, u16 reason)
+int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
+                       struct net_device *dev,
+                       struct ieee80211_channel *chan,
+                       const u8 *bssid, const u8 *prev_bssid,
+                       const u8 *ssid, int ssid_len,
+                       const u8 *ie, int ie_len, bool use_mfp,
+                       struct cfg80211_crypto_settings *crypt)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       wdev_lock(wdev);
+       err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
+                                   ssid, ssid_len, ie, ie_len, use_mfp, crypt);
+       wdev_unlock(wdev);
+
+       return err;
+}
+
+int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
+                          struct net_device *dev, const u8 *bssid,
+                          const u8 *ie, int ie_len, u16 reason)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_deauth_request req;
        int i;
 
+       ASSERT_WDEV_LOCK(wdev);
+
        memset(&req, 0, sizeof(req));
        req.reason_code = reason;
        req.ie = ie;
@@ -402,16 +551,38 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
        if (!req.bss)
                return -ENOTCONN;
 
-       return rdev->ops->deauth(&rdev->wiphy, dev, &req);
+       return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
 }
 
-int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
-                          struct net_device *dev, const u8 *bssid,
-                          const u8 *ie, int ie_len, u16 reason)
+int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
+                        struct net_device *dev, const u8 *bssid,
+                        const u8 *ie, int ie_len, u16 reason)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       wdev_lock(wdev);
+       err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason);
+       wdev_unlock(wdev);
+
+       return err;
+}
+
+static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
+                                   struct net_device *dev, const u8 *bssid,
+                                   const u8 *ie, int ie_len, u16 reason)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_disassoc_request req;
 
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (wdev->sme_state != CFG80211_SME_CONNECTED)
+               return -ENOTCONN;
+
+       if (WARN_ON(!wdev->current_bss))
+               return -ENOTCONN;
+
        memset(&req, 0, sizeof(req));
        req.reason_code = reason;
        req.ie = ie;
@@ -421,7 +592,21 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
        else
                return -ENOTCONN;
 
-       return rdev->ops->disassoc(&rdev->wiphy, dev, &req);
+       return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
+}
+
+int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
+                          struct net_device *dev, const u8 *bssid,
+                          const u8 *ie, int ie_len, u16 reason)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       wdev_lock(wdev);
+       err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason);
+       wdev_unlock(wdev);
+
+       return err;
 }
 
 void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
@@ -431,6 +616,8 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
        struct cfg80211_deauth_request req;
        int i;
 
+       ASSERT_WDEV_LOCK(wdev);
+
        if (!rdev->ops->deauth)
                return;
 
@@ -441,7 +628,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
 
        if (wdev->current_bss) {
                req.bss = &wdev->current_bss->pub;
-               rdev->ops->deauth(&rdev->wiphy, dev, &req);
+               rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
                if (wdev->current_bss) {
                        cfg80211_unhold_bss(wdev->current_bss);
                        cfg80211_put_bss(&wdev->current_bss->pub);
@@ -452,7 +639,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
        for (i = 0; i < MAX_AUTH_BSSES; i++) {
                if (wdev->auth_bsses[i]) {
                        req.bss = &wdev->auth_bsses[i]->pub;
-                       rdev->ops->deauth(&rdev->wiphy, dev, &req);
+                       rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
                        if (wdev->auth_bsses[i]) {
                                cfg80211_unhold_bss(wdev->auth_bsses[i]);
                                cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
@@ -461,7 +648,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
                }
                if (wdev->authtry_bsses[i]) {
                        req.bss = &wdev->authtry_bsses[i]->pub;
-                       rdev->ops->deauth(&rdev->wiphy, dev, &req);
+                       rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
                        if (wdev->authtry_bsses[i]) {
                                cfg80211_unhold_bss(wdev->authtry_bsses[i]);
                                cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);