const u8 *req_ie, size_t req_ie_len,
                     const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
 
+/**
+ * cfg80211_roamed_bss - notify cfg80211 of roaming
+ *
+ * @dev: network device
+ * @bss: entry of bss to which STA got roamed
+ * @req_ie: association request IEs (maybe be %NULL)
+ * @req_ie_len: association request IEs length
+ * @resp_ie: association response IEs (may be %NULL)
+ * @resp_ie_len: assoc response IEs length
+ * @gfp: allocation flags
+ *
+ * This is just a wrapper to notify cfg80211 of roaming event with driver
+ * passing bss to avoid a race in timeout of the bss entry. It should be
+ * called by the underlying driver whenever it roamed from one AP to another
+ * while connected. Drivers which have roaming implemented in firmware
+ * may use this function to avoid a race in bss entry timeout where the bss
+ * entry of the new AP is seen in the driver, but gets timed out by the time
+ * it is accessed in __cfg80211_roamed() due to delay in scheduling
+ * rdev->event_work. In case of any failures, the reference is released
+ * either in cfg80211_roamed_bss() or in __cfg80211_romed(), Otherwise,
+ * it will be released while diconneting from the current bss.
+ */
+void cfg80211_roamed_bss(struct net_device *dev, struct cfg80211_bss *bss,
+                        const u8 *req_ie, size_t req_ie_len,
+                        const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
+
 /**
  * cfg80211_disconnected - notify cfg80211 that connection was dropped
  *
 
 EXPORT_SYMBOL(cfg80211_connect_result);
 
 void __cfg80211_roamed(struct wireless_dev *wdev,
-                      struct ieee80211_channel *channel,
-                      const u8 *bssid,
+                      struct cfg80211_bss *bss,
                       const u8 *req_ie, size_t req_ie_len,
                       const u8 *resp_ie, size_t resp_ie_len)
 {
-       struct cfg80211_bss *bss;
 #ifdef CONFIG_CFG80211_WEXT
        union iwreq_data wrqu;
 #endif
-
        ASSERT_WDEV_LOCK(wdev);
 
        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
                    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
-               return;
+               goto out;
 
        if (wdev->sme_state != CFG80211_SME_CONNECTED)
-               return;
+               goto out;
 
        /* internal error -- how did we get to CONNECTED w/o BSS? */
        if (WARN_ON(!wdev->current_bss)) {
-               return;
+               goto out;
        }
 
        cfg80211_unhold_bss(wdev->current_bss);
        cfg80211_put_bss(&wdev->current_bss->pub);
        wdev->current_bss = NULL;
 
-       bss = cfg80211_get_bss(wdev->wiphy, channel, bssid,
-                              wdev->ssid, wdev->ssid_len,
-                              WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
-
-       if (WARN_ON(!bss))
-               return;
-
        cfg80211_hold_bss(bss_from_pub(bss));
        wdev->current_bss = bss_from_pub(bss);
 
-       nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), wdev->netdev, bssid,
+       nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), wdev->netdev, bss->bssid,
                            req_ie, req_ie_len, resp_ie, resp_ie_len,
                            GFP_KERNEL);
 
 
        memset(&wrqu, 0, sizeof(wrqu));
        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-       memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
-       memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN);
+       memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN);
+       memcpy(wdev->wext.prev_bssid, bss->bssid, ETH_ALEN);
        wdev->wext.prev_bssid_valid = true;
        wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL);
 #endif
+
+       return;
+out:
+       cfg80211_put_bss(bss);
 }
 
 void cfg80211_roamed(struct net_device *dev,
                     const u8 *bssid,
                     const u8 *req_ie, size_t req_ie_len,
                     const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_bss *bss;
+
+       CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED);
+
+       bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid,
+                              wdev->ssid_len, WLAN_CAPABILITY_ESS,
+                              WLAN_CAPABILITY_ESS);
+       if (WARN_ON(!bss))
+               return;
+
+       cfg80211_roamed_bss(dev, bss, req_ie, req_ie_len, resp_ie,
+                           resp_ie_len, gfp);
+}
+EXPORT_SYMBOL(cfg80211_roamed);
+
+void cfg80211_roamed_bss(struct net_device *dev,
+                        struct cfg80211_bss *bss, const u8 *req_ie,
+                        size_t req_ie_len, const u8 *resp_ie,
+                        size_t resp_ie_len, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 
        CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED);
 
+       if (WARN_ON(!bss))
+               return;
+
        ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
-       if (!ev)
+       if (!ev) {
+               cfg80211_put_bss(bss);
                return;
+       }
 
        ev->type = EVENT_ROAMED;
-       ev->rm.channel = channel;
-       memcpy(ev->rm.bssid, bssid, ETH_ALEN);
        ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev);
        ev->rm.req_ie_len = req_ie_len;
        memcpy((void *)ev->rm.req_ie, req_ie, req_ie_len);
        ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
        ev->rm.resp_ie_len = resp_ie_len;
        memcpy((void *)ev->rm.resp_ie, resp_ie, resp_ie_len);
+       ev->rm.bss = bss;
 
        spin_lock_irqsave(&wdev->event_lock, flags);
        list_add_tail(&ev->list, &wdev->event_list);
        spin_unlock_irqrestore(&wdev->event_lock, flags);
        queue_work(cfg80211_wq, &rdev->event_work);
 }
-EXPORT_SYMBOL(cfg80211_roamed);
+EXPORT_SYMBOL(cfg80211_roamed_bss);
 
 void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
                             size_t ie_len, u16 reason, bool from_ap)