aboutsummaryrefslogtreecommitdiffstats
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 {
564 * @NL80211_ATTR_RESP_IE: (Re)association response information elements as 564 * @NL80211_ATTR_RESP_IE: (Re)association response information elements as
565 * sent by peer, for ROAM and successful CONNECT events. 565 * sent by peer, for ROAM and successful CONNECT events.
566 * 566 *
567 * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE
568 * commands to specify using a reassociate frame
569 *
567 * @NL80211_ATTR_MAX: highest attribute number currently defined 570 * @NL80211_ATTR_MAX: highest attribute number currently defined
568 * @__NL80211_ATTR_AFTER_LAST: internal use 571 * @__NL80211_ATTR_AFTER_LAST: internal use
569 */ 572 */
@@ -687,6 +690,8 @@ enum nl80211_attrs {
687 NL80211_ATTR_REQ_IE, 690 NL80211_ATTR_REQ_IE,
688 NL80211_ATTR_RESP_IE, 691 NL80211_ATTR_RESP_IE,
689 692
693 NL80211_ATTR_PREV_BSSID,
694
690 /* add attributes here, update the policy in nl80211.c */ 695 /* add attributes here, update the policy in nl80211.c */
691 696
692 __NL80211_ATTR_AFTER_LAST, 697 __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 {
664 * @ie_len: Length of ie buffer in octets 664 * @ie_len: Length of ie buffer in octets
665 * @use_mfp: Use management frame protection (IEEE 802.11w) in this association 665 * @use_mfp: Use management frame protection (IEEE 802.11w) in this association
666 * @crypto: crypto settings 666 * @crypto: crypto settings
667 * @prev_bssid: previous BSSID, if not %NULL use reassociate frame
667 */ 668 */
668struct cfg80211_assoc_request { 669struct cfg80211_assoc_request {
669 struct cfg80211_bss *bss; 670 struct cfg80211_bss *bss;
670 const u8 *ie; 671 const u8 *ie, *prev_bssid;
671 size_t ie_len; 672 size_t ie_len;
672 struct cfg80211_crypto_settings crypto; 673 struct cfg80211_crypto_settings crypto;
673 bool use_mfp; 674 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,
1256 sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; 1256 sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED;
1257 } 1257 }
1258 1258
1259 if (req->prev_bssid) {
1260 sdata->u.mgd.flags |= IEEE80211_STA_PREV_BSSID_SET;
1261 memcpy(sdata->u.mgd.prev_bssid, req->prev_bssid, ETH_ALEN);
1262 } else
1263 sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
1264
1259 if (req->crypto.control_port) 1265 if (req->crypto.control_port)
1260 sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; 1266 sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT;
1261 else 1267 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,
879 ieee80211_rx_bss_put(local, bss); 879 ieee80211_rx_bss_put(local, bss);
880 } 880 }
881 881
882 ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET;
883 memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN);
884
885 ifmgd->last_probe = jiffies; 882 ifmgd->last_probe = jiffies;
886 ieee80211_led_assoc(local, 1); 883 ieee80211_led_assoc(local, 1);
887 884
@@ -1470,10 +1467,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
1470 if (status_code != WLAN_STATUS_SUCCESS) { 1467 if (status_code != WLAN_STATUS_SUCCESS) {
1471 printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", 1468 printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
1472 sdata->dev->name, status_code); 1469 sdata->dev->name, status_code);
1473 /* if this was a reassociation, ensure we try a "full"
1474 * association next time. This works around some broken APs
1475 * which do not correctly reject reassociation requests. */
1476 ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
1477 cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, 1470 cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len,
1478 GFP_KERNEL); 1471 GFP_KERNEL);
1479 /* Wait for SME to decide what to do next */ 1472 /* 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,
202 const u8 *ie, int ie_len); 202 const u8 *ie, int ie_len);
203int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, 203int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
204 struct net_device *dev, struct ieee80211_channel *chan, 204 struct net_device *dev, struct ieee80211_channel *chan,
205 const u8 *bssid, const u8 *ssid, int ssid_len, 205 const u8 *bssid, const u8 *prev_bssid,
206 const u8 *ssid, int ssid_len,
206 const u8 *ie, int ie_len, bool use_mfp, 207 const u8 *ie, int ie_len, bool use_mfp,
207 struct cfg80211_crypto_settings *crypt); 208 struct cfg80211_crypto_settings *crypt);
208int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, 209int 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,
335 335
336int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, 336int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
337 struct net_device *dev, struct ieee80211_channel *chan, 337 struct net_device *dev, struct ieee80211_channel *chan,
338 const u8 *bssid, const u8 *ssid, int ssid_len, 338 const u8 *bssid, const u8 *prev_bssid,
339 const u8 *ssid, int ssid_len,
339 const u8 *ie, int ie_len, bool use_mfp, 340 const u8 *ie, int ie_len, bool use_mfp,
340 struct cfg80211_crypto_settings *crypt) 341 struct cfg80211_crypto_settings *crypt)
341{ 342{
@@ -353,6 +354,7 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
353 req.ie_len = ie_len; 354 req.ie_len = ie_len;
354 memcpy(&req.crypto, crypt, sizeof(req.crypto)); 355 memcpy(&req.crypto, crypt, sizeof(req.crypto));
355 req.use_mfp = use_mfp; 356 req.use_mfp = use_mfp;
357 req.prev_bssid = prev_bssid;
356 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, 358 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
357 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); 359 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
358 if (!req.bss) 360 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 = {
71 [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, 71 [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
72 72
73 [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, 73 [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
74 [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN },
74 75
75 [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, 76 [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
76 .len = WLAN_MAX_KEY_LEN }, 77 .len = WLAN_MAX_KEY_LEN },
@@ -3187,7 +3188,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3187 struct net_device *dev; 3188 struct net_device *dev;
3188 struct cfg80211_crypto_settings crypto; 3189 struct cfg80211_crypto_settings crypto;
3189 struct ieee80211_channel *chan; 3190 struct ieee80211_channel *chan;
3190 const u8 *bssid, *ssid, *ie = NULL; 3191 const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
3191 int err, ssid_len, ie_len = 0; 3192 int err, ssid_len, ie_len = 0;
3192 bool use_mfp = false; 3193 bool use_mfp = false;
3193 3194
@@ -3248,10 +3249,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3248 } 3249 }
3249 } 3250 }
3250 3251
3252 if (info->attrs[NL80211_ATTR_PREV_BSSID])
3253 prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
3254
3251 err = nl80211_crypto_settings(info, &crypto, 1); 3255 err = nl80211_crypto_settings(info, &crypto, 1);
3252 if (!err) 3256 if (!err)
3253 err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, ssid, 3257 err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
3254 ssid_len, ie, ie_len, use_mfp, 3258 ssid, ssid_len, ie, ie_len, use_mfp,
3255 &crypto); 3259 &crypto);
3256 3260
3257out: 3261out:
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)
125 case CFG80211_CONN_ASSOCIATE_NEXT: 125 case CFG80211_CONN_ASSOCIATE_NEXT:
126 BUG_ON(!drv->ops->assoc); 126 BUG_ON(!drv->ops->assoc);
127 wdev->conn->state = CFG80211_CONN_ASSOCIATING; 127 wdev->conn->state = CFG80211_CONN_ASSOCIATING;
128 /*
129 * We could, later, implement roaming here and then actually
130 * set prev_bssid to non-NULL. But then we need to be aware
131 * that some APs don't like that -- so we'd need to retry
132 * the association.
133 */
128 err = cfg80211_mlme_assoc(drv, wdev->netdev, 134 err = cfg80211_mlme_assoc(drv, wdev->netdev,
129 params->channel, params->bssid, 135 params->channel, params->bssid, NULL,
130 params->ssid, params->ssid_len, 136 params->ssid, params->ssid_len,
131 params->ie, params->ie_len, 137 params->ie, params->ie_len,
132 false, &params->crypto); 138 false, &params->crypto);