From patchwork Sat Feb 6 13:20:16 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave X-Patchwork-Id: 77510 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o16DKmYx007444 for ; Sat, 6 Feb 2010 13:20:48 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755671Ab0BFNUr (ORCPT ); Sat, 6 Feb 2010 08:20:47 -0500 Received: from mail-ew0-f228.google.com ([209.85.219.228]:53889 "EHLO mail-ew0-f228.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755632Ab0BFNUq (ORCPT ); Sat, 6 Feb 2010 08:20:46 -0500 Received: by mail-ew0-f228.google.com with SMTP id 28so944897ewy.28 for ; Sat, 06 Feb 2010 05:20:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=gamma; h=domainkey-signature:received:received:received:from:to:cc:subject :date:message-id:x-mailer:in-reply-to:references; bh=C4zeGJKxahfVBJXTJ5O83UFMvSOKYH+N4HQzK1Vfefo=; b=VjAikw73L5qGA1vggX1GoeDNVT55QjthumgmoZXJrel8dWzj5QgZB4EkqeXfYujUmq qlcXIFN4jr6fv3oEplhhSNuuQCNKlGI3yq+jxM/D9YvGaXOXeuJ2Iecv80Ta4hXUk6u5 gA+IwxUExH2QgKs30fDVF2CMSbdIlRrDZq+Sg= DomainKey-Signature: a=rsa-sha1; c=nofws; d=googlemail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=kTh/RA/ZuDAhY3rZxKPUlAnpFlPtKLMdnfdhpeGsFRkdd0vWLqDVq2b57xfjr+iWHA rREB2dTmGaolQEV1JejGox8uSIDQtb9GynIIVrDNIKle4Hw9eA6tjiYlsZlIMiHPgzXj O1+iYst6iLi/3hbBnvvuJL6ej4ee+gGtmlZ0k= Received: by 10.213.96.198 with SMTP id i6mr3519669ebn.45.1265462439725; Sat, 06 Feb 2010 05:20:39 -0800 (PST) Received: from borken (5e040fbf.bb.sky.com [94.4.15.191]) by mx.google.com with ESMTPS id 13sm1690944ewy.1.2010.02.06.05.20.37 (version=TLSv1/SSLv3 cipher=RC4-MD5); Sat, 06 Feb 2010 05:20:39 -0800 (PST) Received: by borken (sSMTP sendmail emulation); Sat, 06 Feb 2010 13:20:37 +0000 From: David Kilroy To: linux-wireless@vger.kernel.org Cc: holgerschurig@gmail.com, sameo@linux.intel.com, dcbw@redhat.com, David Kilroy Subject: [RFC 2/2] cfg80211: scan for missing BSS on connect completion Date: Sat, 6 Feb 2010 13:20:16 +0000 Message-Id: <1265462416-7547-3-git-send-email-kilroyd@googlemail.com> X-Mailer: git-send-email 1.6.4.4 In-Reply-To: <1265462416-7547-1-git-send-email-kilroyd@googlemail.com> References: <1265462416-7547-1-git-send-email-kilroyd@googlemail.com> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Sat, 06 Feb 2010 13:20:48 +0000 (UTC) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a3f0a7e..67bb8f5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1420,6 +1420,7 @@ extern void wiphy_free(struct wiphy *wiphy); struct cfg80211_conn; struct cfg80211_internal_bss; struct cfg80211_cached_keys; +struct cfg80211_conn2; #define MAX_AUTH_BSSES 4 @@ -1471,6 +1472,8 @@ struct wireless_dev { struct cfg80211_conn *conn; struct cfg80211_cached_keys *connect_keys; + struct cfg80211_conn2 *conn2; /* TODO: Rename */ + struct list_head event_list; spinlock_t event_lock; diff --git a/net/wireless/scan.c b/net/wireless/scan.c index e3d0957..140da4c 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -39,6 +39,11 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) * This must be before sending the other events! * Otherwise, wpa_supplicant gets completely confused with * wext events. + * + * At the moment this will either call cfg80211_sme_scan_done + * or cfg80211_complete_connect. The former should only get + * called if the device supports ops->auth & ops->assoc, the + * latter if the device supports ops->connect. */ if (rdev->async_scan_cb) { rdev->async_scan_cb(dev); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 2ef83b7..6134332 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -34,6 +34,15 @@ struct cfg80211_conn { bool auto_auth, prev_bssid_valid; }; +/* TODO: This struct needs renaming */ +struct cfg80211_conn2 { + struct ieee80211_channel *channel; + u8 bssid[ETH_ALEN]; +}; + +static void __cfg80211_complete_connect(struct net_device *dev, + struct cfg80211_bss *bss); + bool cfg80211_is_all_idle(void) { struct cfg80211_registered_device *rdev; @@ -385,6 +394,62 @@ void cfg80211_sme_failed_assoc(struct wireless_dev *wdev) schedule_work(&rdev->conn_work); } +static void __cfg80211_complete_connect(struct net_device *dev, + struct cfg80211_bss *bss) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + u8 *country_ie; + + cfg80211_hold_bss(bss_from_pub(bss)); + wdev->current_bss = bss_from_pub(bss); + + wdev->sme_state = CFG80211_SME_CONNECTED; + cfg80211_upload_connect_keys(wdev); + + country_ie = (u8 *) ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); + + if (!country_ie) + return; + + /* + * ieee80211_bss_get_ie() ensures we can access: + * - country_ie + 2, the start of the country ie data, and + * - and country_ie[1] which is the IE length + */ + regulatory_hint_11d(wdev->wiphy, + bss->channel->band, + country_ie + 2, + country_ie[1]); +} + +void cfg80211_complete_connect(struct net_device *dev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); + wdev_lock(wdev); + + if (wdev->conn2) { + struct cfg80211_bss *bss; + + bss = cfg80211_get_bss(wdev->wiphy, NULL, wdev->conn2->bssid, + wdev->ssid, wdev->ssid_len, + WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); + + if (WARN_ON(!bss)) + wdev->sme_state = CFG80211_SME_IDLE; + else + __cfg80211_complete_connect(dev, bss); + + kfree(wdev->conn2); + wdev->conn2 = NULL; + } + + wdev_unlock(wdev); + mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); +} + void __cfg80211_connect_result(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, @@ -392,7 +457,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, struct cfg80211_bss *bss) { struct wireless_dev *wdev = dev->ieee80211_ptr; - u8 *country_ie; #ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif @@ -462,29 +526,58 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); - if (WARN_ON(!bss)) - return; + if (!bss) { + struct cfg80211_scan_request *request; + int err; + + /* The driver hasn't reported any beacons or probe + * responses for the BSS that we've connected + * with. Trigger a scan to get it. + * + * Record the BSSID we connected with, so we know what + * to look for later. + * + * Then do a scan on the channel (if specified), + * specifying the SSID. + */ + memcpy(wdev->conn2->bssid, bssid, ETH_ALEN); - cfg80211_hold_bss(bss_from_pub(bss)); - wdev->current_bss = bss_from_pub(bss); + request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) + + sizeof(request->channels[0]), + GFP_KERNEL); + if (!request) + return; - wdev->sme_state = CFG80211_SME_CONNECTED; - cfg80211_upload_connect_keys(wdev); + /* Would be better if we knew the channel of the AP we + * connected to. Is it available in one of the IEs? */ + if (wdev->conn2->channel) { + request->channels[0] = wdev->conn2->channel; + request->n_channels = 1; + request->ssids = (void *) &request->channels[1]; + } else + request->ssids = (void *) &request->channels[0]; - country_ie = (u8 *) ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); + request->n_ssids = 1; - if (!country_ie) - return; + memcpy(request->ssids[0].ssid, wdev->ssid, wdev->ssid_len); + request->ssids[0].ssid_len = wdev->ssid_len; + + request->dev = dev; + request->wiphy = wdev->wiphy; + + err = cfg80211_async_scan(wdev, request, false, + cfg80211_complete_connect); + if (err) { + kfree(request); + wdev->sme_state = CFG80211_SME_IDLE; + } + } else { + kfree(wdev->conn2); + wdev->conn2 = NULL; + + __cfg80211_complete_connect(dev, bss); + }; - /* - * ieee80211_bss_get_ie() ensures we can access: - * - country_ie + 2, the start of the country ie data, and - * - and country_ie[1] which is the IE length - */ - regulatory_hint_11d(wdev->wiphy, - bss->channel->band, - country_ie + 2, - country_ie[1]); } void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, @@ -854,10 +947,22 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, return err; } else { + + if (WARN_ON_ONCE(wdev->conn2)) + return -EINPROGRESS; + + wdev->conn2 = kzalloc(sizeof(*wdev->conn2), GFP_KERNEL); + if (!wdev->conn2) + return -ENOMEM; + + wdev->conn2->channel = connect->channel; + wdev->sme_state = CFG80211_SME_CONNECTING; wdev->connect_keys = connkeys; err = rdev->ops->connect(&rdev->wiphy, dev, connect); if (err) { + kfree(wdev->conn2); + wdev->conn2 = NULL; wdev->connect_keys = NULL; wdev->sme_state = CFG80211_SME_IDLE; return err;