cfg80211: let SME control reassociation vs. association
authorJohannes Berg <johannes@sipsolutions.net>
Tue, 7 Jul 2009 12:37:26 +0000 (14:37 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 10 Jul 2009 19:02:30 +0000 (15:02 -0400)
Since we don't really know that well in the kernel,
let's let the SME control whether it wants to use
reassociation or not, by allowing it to give the
previous BSSID in the associate() parameters.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
include/linux/nl80211.h
include/net/cfg80211.h
net/mac80211/cfg.c
net/mac80211/mlme.c
net/wireless/core.h
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/sme.c

index b34c17f52f3ea5d01a243e0015e8ff5546898274..e496a2daf7efdc2c08e86cafbad35719ec3b454a 100644 (file)
@@ -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,
index ca986cc91098f7ebb3e7e5951722102923005810..71847d3c264043d3937a8f4e607ac14b116ddfbf 100644 (file)
@@ -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;
index 0f29cd0580c9c32b379f3bb98b08f80e0f8a3f66..e6d8860f26f290aee0280849dedeb52890279257 100644 (file)
@@ -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
index aa1829ae431d9d1ee0ba68694526577a5c3edd36..24486455e505102203809e73c6699eed865f35db 100644 (file)
@@ -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 */
index 82918f5896a5122940c4967dc3f93af51997a6a8..4554453c116aecb5ee2bcb4f9b866f5c9c0d78fb 100644 (file)
@@ -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,
index 020f33b38467ac8ee570a61bd76b634c3fda17f9..087d3377958f44a0c9705ea76eb94d427c261c96 100644 (file)
@@ -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)
index 723512b48f2eed2382da3fcd9818a4a1042e01d1..44c520c264fc5a804c015a4f68d8a9f71f8100e6 100644 (file)
@@ -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:
index 412161f7b08e55fcd72173aacc223936544cc79a..066a19ef9d731fffe9176e0424cc7d3e3466f6d0 100644 (file)
@@ -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);