*/
 void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr);
 
+/**
+ * __cfg80211_auth_canceled - notify cfg80211 that authentication was canceled
+ * @dev: network device
+ * @addr: The MAC address of the device with which the authentication timed out
+ *
+ * When a pending authentication had no action yet, the driver may decide
+ * to not send a deauth frame, but in that case must calls this function
+ * to tell cfg80211 about this decision. It is only valid to call this
+ * function within the deauth() callback.
+ */
+void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr);
+
 /**
  * cfg80211_send_rx_assoc - notification of processed association
  * @dev: network device
 
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_mgd_work *wk;
        const u8 *bssid = NULL;
+       bool not_auth_yet = false;
 
        mutex_lock(&ifmgd->mtx);
 
        } else list_for_each_entry(wk, &ifmgd->work_list, list) {
                if (&wk->bss->cbss == req->bss) {
                        bssid = req->bss->bssid;
+                       if (wk->state == IEEE80211_MGD_STATE_PROBE)
+                               not_auth_yet = true;
                        list_del(&wk->list);
                        kfree(wk);
                        break;
                }
        }
 
+       /*
+        * If somebody requests authentication and we haven't
+        * sent out an auth frame yet there's no need to send
+        * out a deauth frame either. If the state was PROBE,
+        * then this is the case. If it's AUTH we have sent a
+        * frame, and if it's IDLE we have completed the auth
+        * process already.
+        */
+       if (not_auth_yet) {
+               mutex_unlock(&ifmgd->mtx);
+               __cfg80211_auth_canceled(sdata->dev, bssid);
+               return 0;
+       }
+
        /*
         * cfg80211 should catch this ... but it's racy since
         * we can receive a deauth frame, process it, hand it
 
 }
 EXPORT_SYMBOL(cfg80211_send_disassoc);
 
-void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
+static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr)
 {
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        int i;
        bool done = false;
 
-       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,
-                                         false, NULL);
+       ASSERT_WDEV_LOCK(wdev);
 
        for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
                if (wdev->authtry_bsses[i] &&
        }
 
        WARN_ON(!done);
+}
+
+void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr)
+{
+       __cfg80211_auth_remove(dev->ieee80211_ptr, addr);
+}
+EXPORT_SYMBOL(__cfg80211_auth_canceled);
+
+void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+       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,
+                                         false, NULL);
+
+       __cfg80211_auth_remove(wdev, addr);
 
        wdev_unlock(wdev);
 }