summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/nl80211.h5
-rw-r--r--include/net/cfg80211.h3
-rw-r--r--net/mac80211/cfg.c6
-rw-r--r--net/mac80211/mlme.c7
-rw-r--r--net/wireless/core.h3
-rw-r--r--net/wireless/mlme.c4
-rw-r--r--net/wireless/nl80211.c10
-rw-r--r--net/wireless/sme.c8
8 files changed, 32 insertions, 14 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index b34c17f52f3e..e496a2daf7ef 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -564,6 +564,9 @@ enum nl80211_commands {
* @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
*/
@@ -687,6 +690,8 @@ enum nl80211_attrs {
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,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ca986cc91098..71847d3c2640 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -664,10 +664,11 @@ struct cfg80211_auth_request {
* @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;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 0f29cd0580c9..e6d8860f26f2 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1256,6 +1256,12 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
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
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index aa1829ae431d..24486455e505 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -879,9 +879,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
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);
@@ -1470,10 +1467,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
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 */
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 82918f5896a5..4554453c116a 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -202,7 +202,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
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,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 020f33b38467..087d3377958f 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -335,7 +335,8 @@ int cfg80211_mlme_auth(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)
{
@@ -353,6 +354,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)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 723512b48f2e..44c520c264fc 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -71,6 +71,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
[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 },
@@ -3187,7 +3188,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
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;
@@ -3248,10 +3249,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
}
}
+ 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:
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 412161f7b08e..066a19ef9d73 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -125,8 +125,14 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
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, &params->crypto);