* @NL80211_ATTR_RESP_IE: (Re)association response information elements as
  *     sent by peer, for ROAM and successful CONNECT events.
  *
+ * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE
+ *     commands to specify using a reassociate frame
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
        NL80211_ATTR_REQ_IE,
        NL80211_ATTR_RESP_IE,
 
+       NL80211_ATTR_PREV_BSSID,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
 
  * @ie_len: Length of ie buffer in octets
  * @use_mfp: Use management frame protection (IEEE 802.11w) in this association
  * @crypto: crypto settings
+ * @prev_bssid: previous BSSID, if not %NULL use reassociate frame
  */
 struct cfg80211_assoc_request {
        struct cfg80211_bss *bss;
-       const u8 *ie;
+       const u8 *ie, *prev_bssid;
        size_t ie_len;
        struct cfg80211_crypto_settings crypto;
        bool use_mfp;
 
                sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED;
        }
 
+       if (req->prev_bssid) {
+               sdata->u.mgd.flags |= IEEE80211_STA_PREV_BSSID_SET;
+               memcpy(sdata->u.mgd.prev_bssid, req->prev_bssid, ETH_ALEN);
+       } else
+               sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
+
        if (req->crypto.control_port)
                sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT;
        else
 
                ieee80211_rx_bss_put(local, bss);
        }
 
-       ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET;
-       memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN);
-
        ifmgd->last_probe = jiffies;
        ieee80211_led_assoc(local, 1);
 
        if (status_code != WLAN_STATUS_SUCCESS) {
                printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
                       sdata->dev->name, status_code);
-               /* if this was a reassociation, ensure we try a "full"
-                * association next time. This works around some broken APs
-                * which do not correctly reject reassociation requests. */
-               ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
                cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len,
                                       GFP_KERNEL);
                /* Wait for SME to decide what to do next */
 
                       const u8 *ie, int ie_len);
 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 *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);
 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
 
 
 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 *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)
 {
        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)
 
        [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
 
        [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
+       [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN },
 
        [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
                                    .len = WLAN_MAX_KEY_LEN },
        struct net_device *dev;
        struct cfg80211_crypto_settings crypto;
        struct ieee80211_channel *chan;
-       const u8 *bssid, *ssid, *ie = NULL;
+       const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
        int err, ssid_len, ie_len = 0;
        bool use_mfp = false;
 
                }
        }
 
+       if (info->attrs[NL80211_ATTR_PREV_BSSID])
+               prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
+
        err = nl80211_crypto_settings(info, &crypto, 1);
        if (!err)
-               err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, ssid,
-                                         ssid_len, ie, ie_len, use_mfp,
+               err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
+                                         ssid, ssid_len, ie, ie_len, use_mfp,
                                          &crypto);
 
 out:
 
        case CFG80211_CONN_ASSOCIATE_NEXT:
                BUG_ON(!drv->ops->assoc);
                wdev->conn->state = CFG80211_CONN_ASSOCIATING;
+               /*
+                * We could, later, implement roaming here and then actually
+                * set prev_bssid to non-NULL. But then we need to be aware
+                * that some APs don't like that -- so we'd need to retry
+                * the association.
+                */
                err = cfg80211_mlme_assoc(drv, wdev->netdev,
-                                         params->channel, params->bssid,
+                                         params->channel, params->bssid, NULL,
                                          params->ssid, params->ssid_len,
                                          params->ie, params->ie_len,
                                          false, ¶ms->crypto);