Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: Further improvements to the software scan implementation
From: Johannes Berg @ 2009-07-16  9:46 UTC (permalink / raw)
  To: Helmut Schaa; +Cc: linux-wireless, Luis Rodriguez
In-Reply-To: <200907161138.58874.helmut.schaa@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 869 bytes --]

On Thu, 2009-07-16 at 11:38 +0200, Helmut Schaa wrote:
> Hi,
> 
> as already discussed with Johannes we can further optimize the scan
> implementation by allowing (on an active channel) to send probes as
> soon as any other frame is received (and updated the NAV) instead of
> ever waiting 30ms.

There's even two ways of implementing this:
 1) the easy way -- just check for received frames in mac80211
 2) the good way -- ask the driver to notify us of _any_ received frames
                    or poll the driver or something like that

1) is clearly very easy, but if it's seeing e.g. a control frame or a
frame for a different BSS then the device might not pass it up.

But to be honest, I wouldn't worry about 2) and let Jouni implement it
if he cares :) And if we want to make this improvement, 1) is good for
all hardware anyway.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* Re: [PATCH 09/10] cfg80211: remove WARN_ON in __cfg80211_sme_scan_done
From: Johannes Berg @ 2009-07-16  9:39 UTC (permalink / raw)
  To: Zhu Yi; +Cc: linville, linux-wireless
In-Reply-To: <1247736854-6760-10-git-send-email-yi.zhu@intel.com>

[-- Attachment #1: Type: text/plain, Size: 866 bytes --]

On Thu, 2009-07-16 at 17:34 +0800, Zhu Yi wrote:
> cfg80211_sme_scan_done() can be called (by fullmac cards) with
> wdev->conn == NULL when CFG80211_SME_CONNECTING. We quit silently
> instead of WARN_ON in this case.

Indeed, sorry.

Acked-by: Johannes Berg <johannes@sipsolutions.net>

> Signed-off-by: Zhu Yi <yi.zhu@intel.com>
> ---
>  net/wireless/sme.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/net/wireless/sme.c b/net/wireless/sme.c
> index 10ed366..e7a8851 100644
> --- a/net/wireless/sme.c
> +++ b/net/wireless/sme.c
> @@ -227,7 +227,7 @@ static void __cfg80211_sme_scan_done(struct net_device *dev)
>  	if (wdev->sme_state != CFG80211_SME_CONNECTING)
>  		return;
>  
> -	if (WARN_ON(!wdev->conn))
> +	if (!wdev->conn)
>  		return;
>  
>  	if (wdev->conn->state != CFG80211_CONN_SCANNING &&

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* [PATCH] cfg80211: don't optimise wext calls too much
From: Johannes Berg @ 2009-07-16  9:39 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, Marcel Holtmann

In the wext code I tried to not reconnect all the time
when the user wasn't really sure what they were doing,
like setting the BSSID back to the same value it was.
However, this optimisation should only be done while
associated so that setting the BSSID back to the same
value that it was actually triggers a new association
if not currently associated. To achieve, that, put the
relevant code into the !IDLE case instead.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 net/wireless/wext-sme.c |   40 +++++++++++++++++++++-------------------
 1 file changed, 21 insertions(+), 19 deletions(-)

--- wireless-testing.orig/net/wireless/wext-sme.c	2009-07-16 11:29:00.000000000 +0200
+++ wireless-testing/net/wireless/wext-sme.c	2009-07-16 11:31:00.000000000 +0200
@@ -72,13 +72,14 @@ int cfg80211_mgd_wext_siwfreq(struct net
 	cfg80211_lock_rdev(rdev);
 	wdev_lock(wdev);
 
-	if (wdev->wext.connect.channel == chan) {
-		err = 0;
-		goto out;
-	}
-
 	if (wdev->sme_state != CFG80211_SME_IDLE) {
 		bool event = true;
+
+		if (wdev->wext.connect.channel == chan) {
+			err = 0;
+			goto out;
+		}
+
 		/* if SSID set, we'll try right again, avoid event */
 		if (wdev->wext.connect.ssid_len)
 			event = false;
@@ -164,13 +165,14 @@ int cfg80211_mgd_wext_siwessid(struct ne
 
 	err = 0;
 
-	if (wdev->wext.connect.ssid && len &&
-	    len == wdev->wext.connect.ssid_len &&
-	    memcmp(wdev->wext.connect.ssid, ssid, len) == 0)
-		goto out;
-
 	if (wdev->sme_state != CFG80211_SME_IDLE) {
 		bool event = true;
+
+		if (wdev->wext.connect.ssid && len &&
+		    len == wdev->wext.connect.ssid_len &&
+		    memcmp(wdev->wext.connect.ssid, ssid, len) == 0)
+			goto out;
+
 		/* if SSID set now, we'll try to connect, avoid event */
 		if (len)
 			event = false;
@@ -244,17 +246,17 @@ int cfg80211_mgd_wext_siwap(struct net_d
 	cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy));
 	wdev_lock(wdev);
 
-	err = 0;
-	/* both automatic */
-	if (!bssid && !wdev->wext.connect.bssid)
-		goto out;
+	if (wdev->sme_state != CFG80211_SME_IDLE) {
+		err = 0;
+		/* both automatic */
+		if (!bssid && !wdev->wext.connect.bssid)
+			goto out;
 
-	/* fixed already - and no change */
-	if (wdev->wext.connect.bssid && bssid &&
-	    compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
-		goto out;
+		/* fixed already - and no change */
+		if (wdev->wext.connect.bssid && bssid &&
+		    compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
+			goto out;
 
-	if (wdev->sme_state != CFG80211_SME_IDLE) {
 		err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
 					    dev, WLAN_REASON_DEAUTH_LEAVING,
 					    false);



^ permalink raw reply

* Further improvements to the software scan implementation
From: Helmut Schaa @ 2009-07-16  9:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, Luis Rodriguez

Hi,

as already discussed with Johannes we can further optimize the scan
implementation by allowing (on an active channel) to send probes as
soon as any other frame is received (and updated the NAV) instead of
ever waiting 30ms.

Another optimization I thought of while reading [1] would be to take the
same approach as Intel in their ucode. If a frame is received while
scanning a passive channel switch to active scan mode and send out probes.
That should allow us to shorten the time needed to stay on that channel.
Luis, do you think this is ok in regard to regulatory restrictions?

Thanks,
Helmut

[1] http://sourceforge.net/mailarchive/forum.php?thread_name=200907061428.55840.jung%40ecos.de&forum_name=ipw3945-devel

^ permalink raw reply

* [PATCH 08/10] iwmc3200wifi: remove key caches in driver
From: Zhu Yi @ 2009-07-16  9:34 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Zhu Yi
In-Reply-To: <1247736854-6760-8-git-send-email-yi.zhu@intel.com>

cfg80211 now guarantees keys are set after connecting. We can remove
the key cache code from the driver now.

Signed-off-by: Zhu Yi <yi.zhu@intel.com>
---
 drivers/net/wireless/iwmc3200wifi/cfg80211.c |   43 +-------------------------
 drivers/net/wireless/iwmc3200wifi/commands.c |   29 +-----------------
 2 files changed, 2 insertions(+), 70 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index 0372658..3f5a08f 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -158,34 +158,6 @@ static int iwm_key_init(struct iwm_key *key, u8 key_index,
 	return 0;
 }
 
-static int iwm_reset_profile(struct iwm_priv *iwm)
-{
-	int ret;
-
-	if (!iwm->umac_profile_active)
-		return 0;
-
-	/*
-	 * If there is a current active profile, but no
-	 * default key, it's not worth trying to associate again.
-	 */
-	if (iwm->default_key < 0)
-		return 0;
-
-	/*
-	 * Here we have an active profile, but a key setting changed.
-	 * We thus have to invalidate the current profile, and push the
-	 * new one. Keys will be pushed when association takes place.
-	 */
-	ret = iwm_invalidate_mlme_profile(iwm);
-	if (ret < 0) {
-		IWM_ERR(iwm, "Couldn't invalidate profile\n");
-		return ret;
-	}
-
-	return iwm_send_mlme_profile(iwm);
-}
-
 static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
 				u8 key_index, const u8 *mac_addr,
 				struct key_params *params)
@@ -245,10 +217,6 @@ static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
 	if (key_index == iwm->default_key)
 		iwm->default_key = -1;
 
-	/* If the interface is down, we just cache this */
-	if (!test_bit(IWM_STATUS_READY, &iwm->status))
-		return 0;
-
 	return iwm_set_key(iwm, 1, key);
 }
 
@@ -257,7 +225,6 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
 					u8 key_index)
 {
 	struct iwm_priv *iwm = ndev_to_iwm(ndev);
-	int ret;
 
 	IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
 
@@ -268,15 +235,7 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
 
 	iwm->default_key = key_index;
 
-	/* If the interface is down, we just cache this */
-	if (!test_bit(IWM_STATUS_READY, &iwm->status))
-		return 0;
-
-	ret = iwm_set_tx_key(iwm, key_index);
-	if (ret < 0)
-		return ret;
-
-	return iwm_reset_profile(iwm);
+	return iwm_set_tx_key(iwm, key_index);
 }
 
 int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index e6be297..0d66370 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -584,12 +584,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
 	struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd;
 	struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd;
 
-	/*
-	 * We check if our current profile is valid.
-	 * If not, we dont push the key, we just cache them,
-	 * so that with the next siwsessid call, the keys
-	 * will be actually pushed.
-	 */
 	if (!remove) {
 		ret = iwm_check_profile(iwm);
 		if (ret < 0)
@@ -727,7 +721,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
 
 int iwm_send_mlme_profile(struct iwm_priv *iwm)
 {
-	int ret, i;
+	int ret;
 	struct iwm_umac_profile profile;
 
 	memcpy(&profile, iwm->umac_profile, sizeof(profile));
@@ -742,27 +736,6 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
 		return ret;
 	}
 
-	for (i = 0; i < IWM_NUM_KEYS; i++)
-		if (iwm->keys[i].key_len) {
-			struct iwm_key *key = &iwm->keys[i];
-
-			/* Wait for the profile before sending the keys */
-			wait_event_interruptible_timeout(iwm->mlme_queue,
-			     (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) ||
-			      test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)),
-							 3 * HZ);
-
-			ret = iwm_set_key(iwm, 0, key);
-			if (ret)
-				return ret;
-
-			if (iwm->default_key == i) {
-				ret = iwm_set_tx_key(iwm, i);
-				if (ret)
-					return ret;
-			}
-		}
-
 	return 0;
 }
 
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH 07/10] iwmc3200wifi: make iwm_send_wifi_if_cmd return 0 on success
From: Zhu Yi @ 2009-07-16  9:34 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Zhu Yi
In-Reply-To: <1247736854-6760-7-git-send-email-yi.zhu@intel.com>

We used to return the result of wait_event_interruptible_timeout()
which is the remaining timeout on success. But this information is
not used by any of its callers. So we just return 0 on success.
This fixed a erroneous return value bug for iwm_set_key().

Signed-off-by: Zhu Yi <yi.zhu@intel.com>
---
 drivers/net/wireless/iwmc3200wifi/commands.c |   27 ++++++++++++-------------
 1 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index 0d35afe..e6be297 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -87,8 +87,7 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
 				   test_and_clear_bit(oid, &iwm->wifi_ntfy[0]),
 				   3 * HZ);
 
-		if (!ret)
-			ret = -EBUSY;
+		return ret ? 0 : -EBUSY;
 	}
 
 	return ret;
@@ -480,8 +479,10 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
 	target_cmd.eop = 1;
 
 	ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
-	if (ret < 0)
+	if (ret < 0) {
 		IWM_ERR(iwm, "Couldn't send READ command\n");
+		return ret;
+	}
 
 	/* When succeding, the send_target routine returns the seq number */
 	seq_num = ret;
@@ -501,7 +502,7 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
 
 	kfree(cmd);
 
-	return ret;
+	return 0;
 }
 
 int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
@@ -511,7 +512,7 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
 
 	ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR),
 			      mac_align, sizeof(mac_align));
-	if (ret < 0)
+	if (ret)
 		return ret;
 
 	if (is_valid_ether_addr(mac_align))
@@ -714,7 +715,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
 		ret =  iwm_send_wifi_if_cmd(iwm, &key_remove,
 					    sizeof(struct iwm_umac_key_remove),
 					    1);
-		if (ret < 0)
+		if (ret)
 			return ret;
 
 		iwm->keys[key_idx].key_len = 0;
@@ -736,7 +737,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
 					   sizeof(struct iwm_umac_wifi_if));
 
 	ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1);
-	if (ret < 0) {
+	if (ret) {
 		IWM_ERR(iwm, "Send profile command failed\n");
 		return ret;
 	}
@@ -752,12 +753,12 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
 							 3 * HZ);
 
 			ret = iwm_set_key(iwm, 0, key);
-			if (ret < 0)
+			if (ret)
 				return ret;
 
 			if (iwm->default_key == i) {
 				ret = iwm_set_tx_key(iwm, i);
-				if (ret < 0)
+				if (ret)
 					return ret;
 			}
 		}
@@ -778,15 +779,13 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
 	invalid.reason = WLAN_REASON_UNSPECIFIED;
 
 	ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1);
-	if (ret < 0)
+	if (ret)
 		return ret;
 
 	ret = wait_event_interruptible_timeout(iwm->mlme_queue,
 				(iwm->umac_profile_active == 0), 2 * HZ);
-	if (!ret)
-		return -EBUSY;
 
-	return 0;
+	return ret ? 0 : -EBUSY;
 }
 
 int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags)
@@ -869,7 +868,7 @@ int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
 	}
 
 	ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0);
-	if (ret < 0) {
+	if (ret) {
 		IWM_ERR(iwm, "Couldn't send scan request\n");
 		return ret;
 	}
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH 09/10] cfg80211: remove WARN_ON in __cfg80211_sme_scan_done
From: Zhu Yi @ 2009-07-16  9:34 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Zhu Yi
In-Reply-To: <1247736854-6760-9-git-send-email-yi.zhu@intel.com>

cfg80211_sme_scan_done() can be called (by fullmac cards) with
wdev->conn == NULL when CFG80211_SME_CONNECTING. We quit silently
instead of WARN_ON in this case.

Signed-off-by: Zhu Yi <yi.zhu@intel.com>
---
 net/wireless/sme.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 10ed366..e7a8851 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -227,7 +227,7 @@ static void __cfg80211_sme_scan_done(struct net_device *dev)
 	if (wdev->sme_state != CFG80211_SME_CONNECTING)
 		return;
 
-	if (WARN_ON(!wdev->conn))
+	if (!wdev->conn)
 		return;
 
 	if (wdev->conn->state != CFG80211_CONN_SCANNING &&
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH 05/10] iwmc3200wifi: cfg80211 managed mode port
From: Zhu Yi @ 2009-07-16  9:34 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Samuel Ortiz, Zhu Yi
In-Reply-To: <1247736854-6760-5-git-send-email-yi.zhu@intel.com>

From: Samuel Ortiz <samuel.ortiz@intel.com>

This patch ports iwmc3200wifi to the cfg80211 managed mode API.

Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
---
 drivers/net/wireless/iwmc3200wifi/cfg80211.c |  195 ++++++++++++++++
 drivers/net/wireless/iwmc3200wifi/rx.c       |   16 +-
 drivers/net/wireless/iwmc3200wifi/wext.c     |  320 +++-----------------------
 3 files changed, 239 insertions(+), 292 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index 0aa3895..ee40317 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -305,6 +305,25 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
 	return iwm_reset_profile(iwm);
 }
 
+int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
+			     u8 *mac, struct station_info *sinfo)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(ndev);
+
+	if (memcmp(mac, iwm->bssid, ETH_ALEN))
+		return -ENOENT;
+
+	sinfo->filled |= STATION_INFO_TX_BITRATE;
+	sinfo->txrate.legacy = iwm->rate * 10;
+
+	if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
+		sinfo->filled |= STATION_INFO_SIGNAL;
+		sinfo->signal = iwm->wstats.qual.level;
+	}
+
+	return 0;
+}
+
 
 int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
 {
@@ -500,6 +519,179 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
 	return 0;
 }
 
+static int iwm_set_auth_type(struct iwm_priv *iwm,
+			     enum nl80211_auth_type sme_auth_type)
+{
+	u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+	switch (sme_auth_type) {
+	case NL80211_AUTHTYPE_AUTOMATIC:
+	case NL80211_AUTHTYPE_OPEN_SYSTEM:
+		IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n");
+		*auth_type = UMAC_AUTH_TYPE_OPEN;
+		break;
+	case NL80211_AUTHTYPE_SHARED_KEY:
+		if (iwm->umac_profile->sec.flags &
+		    (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
+			IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n");
+			*auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+		} else {
+			IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n");
+			*auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+		}
+
+		break;
+	default:
+		IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type);
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
+{
+	if (!wpa_version) {
+		iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
+		return 0;
+	}
+
+	if (wpa_version & NL80211_WPA_VERSION_2)
+		iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
+
+	if (wpa_version & NL80211_WPA_VERSION_1)
+		iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
+
+	return 0;
+}
+
+static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast)
+{
+	u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
+		&iwm->umac_profile->sec.mcast_cipher;
+
+	if (!cipher) {
+		*profile_cipher = UMAC_CIPHER_TYPE_NONE;
+		return 0;
+	}
+
+	switch (cipher) {
+	case IW_AUTH_CIPHER_NONE:
+		*profile_cipher = UMAC_CIPHER_TYPE_NONE;
+		break;
+	case WLAN_CIPHER_SUITE_WEP40:
+		*profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
+		break;
+	case WLAN_CIPHER_SUITE_WEP104:
+		*profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
+		break;
+	case WLAN_CIPHER_SUITE_TKIP:
+		*profile_cipher = UMAC_CIPHER_TYPE_TKIP;
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		*profile_cipher = UMAC_CIPHER_TYPE_CCMP;
+		break;
+	default:
+		IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt)
+{
+	u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+	IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
+
+	if (key_mgt == WLAN_AKM_SUITE_8021X)
+		*auth_type = UMAC_AUTH_TYPE_8021X;
+	else if (key_mgt == WLAN_AKM_SUITE_PSK) {
+		if (iwm->umac_profile->sec.flags &
+		    (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
+			*auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+		else
+			*auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+	} else {
+		IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+				 struct cfg80211_connect_params *sme)
+{
+	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+	struct ieee80211_channel *chan = sme->channel;
+	int ret;
+
+	if (!test_bit(IWM_STATUS_READY, &iwm->status))
+		return -EIO;
+
+	if (!sme->ssid)
+		return -EINVAL;
+
+	if (chan)
+		iwm->channel =
+			ieee80211_frequency_to_channel(chan->center_freq);
+
+	iwm->umac_profile->ssid.ssid_len = sme->ssid_len;
+	memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len);
+
+	if (sme->bssid) {
+		IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid);
+		memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN);
+		iwm->umac_profile->bss_num = 1;
+	} else {
+		memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
+		iwm->umac_profile->bss_num = 0;
+	}
+
+	ret = iwm_set_auth_type(iwm, sme->auth_type);
+	if (ret < 0)
+		return ret;
+
+	ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
+	if (ret < 0)
+		return ret;
+
+	if (sme->crypto.n_ciphers_pairwise) {
+		ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0],
+				     true);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false);
+	if (ret < 0)
+		return ret;
+
+	if (sme->crypto.n_akm_suites) {
+		ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]);
+		if (ret < 0)
+			return ret;
+	}
+
+	return iwm_send_mlme_profile(iwm);
+}
+
+static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+				   u16 reason_code)
+{
+	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+	IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active);
+
+	if (iwm->umac_profile_active)
+		return iwm_invalidate_mlme_profile(iwm);
+
+	return 0;
+}
+
 static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
 				    enum tx_power_setting type, int dbm)
 {
@@ -549,8 +741,11 @@ static struct cfg80211_ops iwm_cfg80211_ops = {
 	.get_key = iwm_cfg80211_get_key,
 	.del_key = iwm_cfg80211_del_key,
 	.set_default_key = iwm_cfg80211_set_default_key,
+	.get_station = iwm_cfg80211_get_station,
 	.scan = iwm_cfg80211_scan,
 	.set_wiphy_params = iwm_cfg80211_set_wiphy_params,
+	.connect = iwm_cfg80211_connect,
+	.disconnect = iwm_cfg80211_disconnect,
 	.join_ibss = iwm_cfg80211_join_ibss,
 	.leave_ibss = iwm_cfg80211_leave_ibss,
 	.set_tx_power = iwm_cfg80211_set_txpower,
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 218933b..82b572a 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -503,13 +503,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
 {
 	struct iwm_umac_notif_assoc_complete *complete =
 		(struct iwm_umac_notif_assoc_complete *)buf;
-	union iwreq_data wrqu;
 
 	IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n",
 		     complete->bssid, complete->status);
 
-	memset(&wrqu, 0, sizeof(wrqu));
-
 	clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
 
 	switch (le32_to_cpu(complete->status)) {
@@ -520,7 +517,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
 
 		iwm_link_on(iwm);
 
-		memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN);
+		cfg80211_connect_result(iwm_to_ndev(iwm),
+					complete->bssid,
+					NULL, 0, NULL, 0,
+					WLAN_STATUS_SUCCESS, GFP_KERNEL);
 		break;
 	case UMAC_ASSOC_COMPLETE_FAILURE:
 		clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
@@ -528,6 +528,11 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
 		iwm->channel = 0;
 
 		iwm_link_off(iwm);
+
+		cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid,
+					NULL, 0, NULL, 0,
+					WLAN_STATUS_UNSPECIFIED_FAILURE,
+					GFP_KERNEL);
 	default:
 		break;
 	}
@@ -537,9 +542,6 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
 		return 0;
 	}
 
-	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-	wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL);
-
 	return 0;
 }
 
diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c
index 2e7eaf9..c3c90d5 100644
--- a/drivers/net/wireless/iwmc3200wifi/wext.c
+++ b/drivers/net/wireless/iwmc3200wifi/wext.c
@@ -21,31 +21,11 @@
  *
  */
 
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
 #include <linux/wireless.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
 #include <net/cfg80211.h>
-#include <net/iw_handler.h>
 
 #include "iwm.h"
-#include "umac.h"
 #include "commands.h"
-#include "debug.h"
-
-static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
-{
-	struct iwm_priv *iwm = ndev_to_iwm(dev);
-	struct iw_statistics *wstats = &iwm->wstats;
-
-	if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
-		memset(wstats, 0, sizeof(struct iw_statistics));
-		wstats->qual.updated = IW_QUAL_ALL_INVALID;
-	}
-
-	return wstats;
-}
 
 static int iwm_wext_siwfreq(struct net_device *dev,
 			    struct iw_request_info *info,
@@ -53,14 +33,12 @@ static int iwm_wext_siwfreq(struct net_device *dev,
 {
 	struct iwm_priv *iwm = ndev_to_iwm(dev);
 
-	if (freq->flags == IW_FREQ_AUTO)
-		return 0;
-
-	/* frequency/channel can only be set in IBSS mode */
-	if (iwm->conf.mode != UMAC_MODE_IBSS)
+	switch (iwm->conf.mode) {
+	case UMAC_MODE_IBSS:
+		return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
+	default:
 		return -EOPNOTSUPP;
-
-	return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
+	}
 }
 
 static int iwm_wext_giwfreq(struct net_device *dev,
@@ -69,69 +47,29 @@ static int iwm_wext_giwfreq(struct net_device *dev,
 {
 	struct iwm_priv *iwm = ndev_to_iwm(dev);
 
-	if (iwm->conf.mode == UMAC_MODE_IBSS)
+	switch (iwm->conf.mode) {
+	case UMAC_MODE_IBSS:
 		return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
-
-	freq->e = 0;
-	freq->m = iwm->channel;
-
-	return 0;
+	case UMAC_MODE_BSS:
+		return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
 			  struct sockaddr *ap_addr, char *extra)
 {
 	struct iwm_priv *iwm = ndev_to_iwm(dev);
-	int ret;
-
-	IWM_DBG_WEXT(iwm, DBG, "Set BSSID: %pM\n", ap_addr->sa_data);
 
-	if (iwm->conf.mode == UMAC_MODE_IBSS)
+	switch (iwm->conf.mode) {
+	case UMAC_MODE_IBSS:
 		return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
-
-	if (!test_bit(IWM_STATUS_READY, &iwm->status))
-		return -EIO;
-
-	if (is_zero_ether_addr(ap_addr->sa_data) ||
-	    is_broadcast_ether_addr(ap_addr->sa_data)) {
-		IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
-			     iwm->umac_profile->bssid[0]);
-		memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
-		iwm->umac_profile->bss_num = 0;
-	} else {
-		IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
-			     ap_addr->sa_data);
-		memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
-		       ETH_ALEN);
-		iwm->umac_profile->bss_num = 1;
-	}
-
-	if (iwm->umac_profile_active) {
-		int i;
-
-		if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
-			return 0;
-
-		/*
-		 * If we're clearing the BSSID, and we're associated,
-		 * we have to clear the keys as they're no longer valid.
-		 */
-		if (is_zero_ether_addr(ap_addr->sa_data)) {
-			for (i = 0; i < IWM_NUM_KEYS; i++)
-				iwm->keys[i].key_len = 0;
-		}
-
-		ret = iwm_invalidate_mlme_profile(iwm);
-		if (ret < 0) {
-			IWM_ERR(iwm, "Couldn't invalidate profile\n");
-			return ret;
-		}
+	case UMAC_MODE_BSS:
+		return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
+	default:
+		return -EOPNOTSUPP;
 	}
-
-	if (iwm->umac_profile->ssid.ssid_len)
-		return iwm_send_mlme_profile(iwm);
-
-	return 0;
 }
 
 static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
@@ -143,17 +81,10 @@ static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
 	case UMAC_MODE_IBSS:
 		return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
 	case UMAC_MODE_BSS:
-		if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
-			ap_addr->sa_family = ARPHRD_ETHER;
-			memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
-		} else
-			memset(&ap_addr->sa_data, 0, ETH_ALEN);
-		break;
+		return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
 	default:
 		return -EOPNOTSUPP;
 	}
-
-	return 0;
 }
 
 static int iwm_wext_siwessid(struct net_device *dev,
@@ -161,36 +92,15 @@ static int iwm_wext_siwessid(struct net_device *dev,
 			     struct iw_point *data, char *ssid)
 {
 	struct iwm_priv *iwm = ndev_to_iwm(dev);
-	size_t len = data->length;
-	int ret;
-
-	IWM_DBG_WEXT(iwm, DBG, "Set ESSID: >%s<\n", ssid);
 
-	if (iwm->conf.mode == UMAC_MODE_IBSS)
+	switch (iwm->conf.mode) {
+	case UMAC_MODE_IBSS:
 		return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
-
-	if (!test_bit(IWM_STATUS_READY, &iwm->status))
-		return -EIO;
-
-	if (len > 0 && ssid[len - 1] == '\0')
-		len--;
-
-	if (iwm->umac_profile_active) {
-		if (iwm->umac_profile->ssid.ssid_len == len &&
-		    !memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
-			return 0;
-
-		ret = iwm_invalidate_mlme_profile(iwm);
-		if (ret < 0) {
-			IWM_ERR(iwm, "Couldn't invalidate profile\n");
-			return ret;
-		}
+	case UMAC_MODE_BSS:
+		return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
+	default:
+		return -EOPNOTSUPP;
 	}
-
-	iwm->umac_profile->ssid.ssid_len = len;
-	memcpy(iwm->umac_profile->ssid.ssid, ssid, len);
-
-	return iwm_send_mlme_profile(iwm);
 }
 
 static int iwm_wext_giwessid(struct net_device *dev,
@@ -199,174 +109,14 @@ static int iwm_wext_giwessid(struct net_device *dev,
 {
 	struct iwm_priv *iwm = ndev_to_iwm(dev);
 
-	if (iwm->conf.mode == UMAC_MODE_IBSS)
+	switch (iwm->conf.mode) {
+	case UMAC_MODE_IBSS:
 		return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
-
-	if (!test_bit(IWM_STATUS_READY, &iwm->status))
-		return -EIO;
-
-	data->length = iwm->umac_profile->ssid.ssid_len;
-	if (data->length) {
-		memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
-		data->flags = 1;
-	} else
-		data->flags = 0;
-
-	return 0;
-}
-
-static int iwm_wext_giwrate(struct net_device *dev,
-			    struct iw_request_info *info,
-			    struct iw_param *rate, char *extra)
-{
-	struct iwm_priv *iwm = ndev_to_iwm(dev);
-
-	rate->value = iwm->rate * 1000000;
-
-	return 0;
-}
-
-static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
-{
-	if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
-		iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
-	else if (wpa_version & IW_AUTH_WPA_VERSION_WPA)
-		iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
-	else
-		iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
-
-	return 0;
-}
-
-static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
-{
-	u8 *auth_type = &iwm->umac_profile->sec.auth_type;
-
-	IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
-
-	if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
-		*auth_type = UMAC_AUTH_TYPE_8021X;
-	else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
-		if (iwm->umac_profile->sec.flags &
-		    (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
-			*auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
-		else
-			*auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
-	} else {
-		IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast)
-{
-	u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
-		&iwm->umac_profile->sec.mcast_cipher;
-
-	switch (cipher) {
-	case IW_AUTH_CIPHER_NONE:
-		*profile_cipher = UMAC_CIPHER_TYPE_NONE;
-		break;
-	case IW_AUTH_CIPHER_WEP40:
-		*profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
-		break;
-	case IW_AUTH_CIPHER_TKIP:
-		*profile_cipher = UMAC_CIPHER_TYPE_TKIP;
-		break;
-	case IW_AUTH_CIPHER_CCMP:
-		*profile_cipher = UMAC_CIPHER_TYPE_CCMP;
-		break;
-	case IW_AUTH_CIPHER_WEP104:
-		*profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
-		break;
-	default:
-		IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
-		return -ENOTSUPP;
-	}
-
-	return 0;
-}
-
-static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
-{
-	u8 *auth_type = &iwm->umac_profile->sec.auth_type;
-
-	IWM_DBG_WEXT(iwm, DBG, "auth_alg: 0x%x\n", auth_alg);
-
-	switch (auth_alg) {
-	case IW_AUTH_ALG_OPEN_SYSTEM:
-		*auth_type = UMAC_AUTH_TYPE_OPEN;
-		break;
-	case IW_AUTH_ALG_SHARED_KEY:
-		if (iwm->umac_profile->sec.flags &
-		    (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
-			if (*auth_type == UMAC_AUTH_TYPE_8021X)
-				return -EINVAL;
-			*auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
-		} else {
-			IWM_DBG_WEXT(iwm, DBG, "WEP shared key\n");
-			*auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
-		}
-		break;
-	case IW_AUTH_ALG_LEAP:
-	default:
-		IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg);
-		return -ENOTSUPP;
-	}
-
-	return 0;
-}
-
-static int iwm_wext_siwauth(struct net_device *dev,
-			    struct iw_request_info *info,
-			    struct iw_param *data, char *extra)
-{
-	struct iwm_priv *iwm = ndev_to_iwm(dev);
-	int ret;
-
-	if ((data->flags) &
-	    (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
-	     IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
-		/* We need to invalidate the current profile */
-		if (iwm->umac_profile_active) {
-			ret = iwm_invalidate_mlme_profile(iwm);
-			if (ret < 0) {
-				IWM_ERR(iwm, "Couldn't invalidate profile\n");
-				return ret;
-			}
-		}
-	}
-
-	switch (data->flags & IW_AUTH_INDEX) {
-	case IW_AUTH_WPA_VERSION:
-		return iwm_set_wpa_version(iwm, data->value);
-		break;
-	case IW_AUTH_CIPHER_PAIRWISE:
-		return iwm_set_cipher(iwm, data->value, 1);
-		break;
-	case IW_AUTH_CIPHER_GROUP:
-		return iwm_set_cipher(iwm, data->value, 0);
-		break;
-	case IW_AUTH_KEY_MGMT:
-		return iwm_set_key_mgt(iwm, data->value);
-		break;
-	case IW_AUTH_80211_AUTH_ALG:
-		return iwm_set_auth_alg(iwm, data->value);
-		break;
+	case UMAC_MODE_BSS:
+		return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
 	default:
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 	}
-
-	return 0;
-}
-
-static int iwm_wext_giwauth(struct net_device *dev,
-			    struct iw_request_info *info,
-			    struct iw_param *data, char *extra)
-{
-	return 0;
 }
 
 static const iw_handler iwm_handlers[] =
@@ -404,7 +154,7 @@ static const iw_handler iwm_handlers[] =
 	(iw_handler) NULL,				/* -- hole -- */
 	(iw_handler) NULL,				/* -- hole -- */
 	(iw_handler) NULL,				/* SIOCSIWRATE */
-	(iw_handler) iwm_wext_giwrate,			/* SIOCGIWRATE */
+	(iw_handler) cfg80211_wext_giwrate,		/* SIOCGIWRATE */
 	(iw_handler) cfg80211_wext_siwrts,		/* SIOCSIWRTS */
 	(iw_handler) cfg80211_wext_giwrts,		/* SIOCGIWRTS */
 	(iw_handler) cfg80211_wext_siwfrag,	        /* SIOCSIWFRAG */
@@ -419,10 +169,10 @@ static const iw_handler iwm_handlers[] =
 	(iw_handler) cfg80211_wext_giwpower,		/* SIOCGIWPOWER */
 	(iw_handler) NULL,				/* -- hole -- */
 	(iw_handler) NULL,				/* -- hole -- */
-	(iw_handler) NULL,                              /* SIOCSIWGENIE */
+	(iw_handler) cfg80211_wext_siwgenie,            /* SIOCSIWGENIE */
 	(iw_handler) NULL,				/* SIOCGIWGENIE */
-	(iw_handler) iwm_wext_siwauth,			/* SIOCSIWAUTH */
-	(iw_handler) iwm_wext_giwauth,			/* SIOCGIWAUTH */
+	(iw_handler) cfg80211_wext_siwauth,		/* SIOCSIWAUTH */
+	(iw_handler) cfg80211_wext_giwauth,		/* SIOCGIWAUTH */
 	(iw_handler) cfg80211_wext_siwencodeext,	/* SIOCSIWENCODEEXT */
 	(iw_handler) NULL,				/* SIOCGIWENCODEEXT */
 	(iw_handler) NULL,				/* SIOCSIWPMKSA */
@@ -432,6 +182,6 @@ static const iw_handler iwm_handlers[] =
 const struct iw_handler_def iwm_iw_handler_def = {
 	.num_standard	= ARRAY_SIZE(iwm_handlers),
 	.standard	= (iw_handler *) iwm_handlers,
-	.get_wireless_stats = iwm_get_wireless_stats,
+	.get_wireless_stats = cfg80211_wireless_stats,
 };
 
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH 06/10] iwmc3200wifi: remove setting WEP keys before setting essid support
From: Zhu Yi @ 2009-07-16  9:34 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Zhu Yi
In-Reply-To: <1247736854-6760-6-git-send-email-yi.zhu@intel.com>

The recent cfg80211 "rework key operation" patch from Johannes Berg
makes sure keys are set only after the connection has been
established. So we can remove the setting WEP keys before essid
support from the driver.

Signed-off-by: Zhu Yi <yi.zhu@intel.com>
---
 drivers/net/wireless/iwmc3200wifi/cfg80211.c |   26 --------------------------
 1 files changed, 0 insertions(+), 26 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index ee40317..0372658 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -203,32 +203,6 @@ static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
 		return ret;
 	}
 
-	/*
-	 * The WEP keys can be set before or after setting the essid.
-	 * We need to handle both cases by simply pushing the keys after
-	 * we send the profile.
-	 * If the profile is not set yet (i.e. we're pushing keys before
-	 * the essid), we set the cipher appropriately.
-	 * If the profile is set, we havent associated yet because our
-	 * cipher was incorrectly set. So we invalidate and send the
-	 * profile again.
-	 */
-	if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-	    key->cipher == WLAN_CIPHER_SUITE_WEP104) {
-		u8 *ucast_cipher = &iwm->umac_profile->sec.ucast_cipher;
-		u8 *mcast_cipher = &iwm->umac_profile->sec.mcast_cipher;
-
-		IWM_DBG_WEXT(iwm, DBG, "WEP key\n");
-
-		if (key->cipher == WLAN_CIPHER_SUITE_WEP40)
-			*ucast_cipher = *mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
-		if (key->cipher == WLAN_CIPHER_SUITE_WEP104)
-			*ucast_cipher = *mcast_cipher =
-				UMAC_CIPHER_TYPE_WEP_104;
-
-		return iwm_reset_profile(iwm);
-	}
-
 	return iwm_set_key(iwm, 0, key);
 }
 
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH 04/10] iwmc3200wifi: use correct debug level
From: Zhu Yi @ 2009-07-16  9:34 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Zhu Yi
In-Reply-To: <1247736854-6760-4-git-send-email-yi.zhu@intel.com>

This patch uses TX and RX instead of NTF debug levels in some hot
paths.

Signed-off-by: Zhu Yi <yi.zhu@intel.com>
---
 drivers/net/wireless/iwmc3200wifi/rx.c |   32 ++++++++++++++++----------------
 1 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 9fb498b..218933b 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -218,17 +218,17 @@ static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf,
 		(buf + sizeof(struct iwm_umac_wifi_in_hdr));
 	hdr = (struct iwm_umac_wifi_in_hdr *)buf;
 
-	IWM_DBG_NTF(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
-
-	IWM_DBG_NTF(iwm, DBG, "Seqnum: %d\n",
-		    le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
-	IWM_DBG_NTF(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
-	IWM_DBG_NTF(iwm, DBG, "\tRetry cnt: %d\n",
-		    le16_to_cpu(tx_resp->retry_cnt));
-	IWM_DBG_NTF(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
-	IWM_DBG_NTF(iwm, DBG, "\tByte cnt: %d\n",
-		    le16_to_cpu(tx_resp->byte_cnt));
-	IWM_DBG_NTF(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
+	IWM_DBG_TX(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
+
+	IWM_DBG_TX(iwm, DBG, "Seqnum: %d\n",
+		   le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
+	IWM_DBG_TX(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
+	IWM_DBG_TX(iwm, DBG, "\tRetry cnt: %d\n",
+		   le16_to_cpu(tx_resp->retry_cnt));
+	IWM_DBG_TX(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
+	IWM_DBG_TX(iwm, DBG, "\tByte cnt: %d\n",
+		   le16_to_cpu(tx_resp->byte_cnt));
+	IWM_DBG_TX(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
 
 	return 0;
 }
@@ -418,8 +418,8 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
 			if (IS_ERR(ticket_node))
 				return PTR_ERR(ticket_node);
 
-			IWM_DBG_NTF(iwm, DBG, "TICKET RELEASE(%d)\n",
-				    ticket->id);
+			IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n",
+				   ticket->id);
 			list_add_tail(&ticket_node->node, &iwm->rx_tickets);
 
 			/*
@@ -454,15 +454,15 @@ static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf,
 	u16 id, buf_offset;
 	u32 packet_size;
 
-	IWM_DBG_NTF(iwm, DBG, "\n");
+	IWM_DBG_RX(iwm, DBG, "\n");
 
 	wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf;
 	id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num);
 	buf_offset = sizeof(struct iwm_umac_wifi_in_hdr);
 	packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr);
 
-	IWM_DBG_NTF(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
-		    wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
+	IWM_DBG_RX(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
+		   wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
 	IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id);
 	IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size);
 
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH 03/10] iwmc3200wifi: set cipher_suites before registering wiphy
From: Zhu Yi @ 2009-07-16  9:34 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Zhu Yi
In-Reply-To: <1247736854-6760-3-git-send-email-yi.zhu@intel.com>

We need to specify all the cipher suites we supported. Otherwise
cfg80211_validate_key_settings() will fail when we are setting
keys.

Signed-off-by: Zhu Yi <yi.zhu@intel.com>
---
 drivers/net/wireless/iwmc3200wifi/cfg80211.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index 54bebba..0aa3895 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -558,6 +558,13 @@ static struct cfg80211_ops iwm_cfg80211_ops = {
 	.set_power_mgmt = iwm_cfg80211_set_power_mgmt,
 };
 
+static const u32 cipher_suites[] = {
+	WLAN_CIPHER_SUITE_WEP40,
+	WLAN_CIPHER_SUITE_WEP104,
+	WLAN_CIPHER_SUITE_TKIP,
+	WLAN_CIPHER_SUITE_CCMP,
+};
+
 struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
 {
 	int ret = 0;
@@ -600,6 +607,9 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
 	wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz;
 	wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 
+	wdev->wiphy->cipher_suites = cipher_suites;
+	wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
 	ret = wiphy_register(wdev->wiphy);
 	if (ret < 0) {
 		dev_err(dev, "Couldn't register wiphy device\n");
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH 02/10] iwmc3200wifi: hardware does not support IP checksum
From: Zhu Yi @ 2009-07-16  9:34 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Zhu Yi
In-Reply-To: <1247736854-6760-2-git-send-email-yi.zhu@intel.com>

The iwmc3200wifi hardware doesn't support IP checksum. So mark the
skb->ip_summed to CHECKSUM_NONE instead of CHECKSUM_UNNECESSARY.

Signed-off-by: Zhu Yi <yi.zhu@intel.com>
---
 drivers/net/wireless/iwmc3200wifi/rx.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 59ef69c..9fb498b 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -1359,7 +1359,7 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
 
 		skb->dev = iwm_to_ndev(iwm);
 		skb->protocol = eth_type_trans(skb, ndev);
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		skb->ip_summed = CHECKSUM_NONE;
 		memset(skb->cb, 0, sizeof(skb->cb));
 
 		ndev->stats.rx_packets++;
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH 00/09] iwmc3200wifi updates
From: Zhu Yi @ 2009-07-16  9:34 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Zhu Yi

Hi,

Here are some patches for iwmc3200wifi driver to adapt to recent
cfg80211 changes.

[PATCH 01/09] iwmc3200wifi: fix UMAC INIT_COMPLETE notification handling
[PATCH 02/09] iwmc3200wifi: hardware does not support IP checksum
[PATCH 03/09] iwmc3200wifi: set cipher_suites before registering wiphy
[PATCH 04/09] iwmc3200wifi: use correct debug level
[PATCH 05/09] iwmc3200wifi: cfg80211 managed mode port
[PATCH 06/09] iwmc3200wifi: remove setting WEP keys before setting essid support
[PATCH 07/09] iwmc3200wifi: make iwm_send_wifi_if_cmd return 0 on success
[PATCH 08/09] iwmc3200wifi: remove key caches in driver
[PATCH 09/09] cfg80211: remove WARN_ON in __cfg80211_sme_scan_done

Thanks,
-yi

^ permalink raw reply

* [PATCH 01/10] iwmc3200wifi: fix UMAC INIT_COMPLETE notification handling
From: Zhu Yi @ 2009-07-16  9:34 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Zhu Yi
In-Reply-To: <1247736854-6760-1-git-send-email-yi.zhu@intel.com>

The patch fixes the missing UMAC iwm_umac_wifi_in_hdr header in
the UMAC INIT_COMPLETE (iwm_umac_notif_init_complete) notification.

Signed-off-by: Zhu Yi <yi.zhu@intel.com>
---
 drivers/net/wireless/iwmc3200wifi/rx.c   |    1 -
 drivers/net/wireless/iwmc3200wifi/umac.h |    6 ++++++
 2 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 3909477..59ef69c 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -102,7 +102,6 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf,
 	error = (struct iwm_umac_notif_error *)buf;
 	fw_err = &error->err;
 
-
 	IWM_ERR(iwm, "%cMAC FW ERROR:\n",
 	 (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U');
 	IWM_ERR(iwm, "\tCategory:    %d\n", le32_to_cpu(fw_err->category));
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h
index 0af2a3c..c5a14ae 100644
--- a/drivers/net/wireless/iwmc3200wifi/umac.h
+++ b/drivers/net/wireless/iwmc3200wifi/umac.h
@@ -615,6 +615,7 @@ struct iwm_umac_notif_alive {
 } __attribute__ ((packed));
 
 struct iwm_umac_notif_init_complete {
+	struct iwm_umac_wifi_in_hdr hdr;
 	__le16 status;
 	__le16 reserved;
 } __attribute__ ((packed));
@@ -643,6 +644,11 @@ struct iwm_fw_error_hdr {
 	__le32 umac_status;
 	__le32 lmac_status;
 	__le32 sdio_status;
+	__le32 dbm_sample_ctrl;
+	__le32 dbm_buf_base;
+	__le32 dbm_buf_end;
+	__le32 dbm_buf_write_ptr;
+	__le32 dbm_buf_cycle_cnt;
 } __attribute__ ((packed));
 
 struct iwm_umac_notif_error {
-- 
1.6.0.4


^ permalink raw reply related

* Re: [RFC/RFT 5/5] mac80211: implement basic background scanning
From: Johannes Berg @ 2009-07-16  9:25 UTC (permalink / raw)
  To: Helmut Schaa; +Cc: linux-wireless
In-Reply-To: <200907161109.40471.helmut.schaa@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 5093 bytes --]

On Thu, 2009-07-16 at 11:09 +0200, Helmut Schaa wrote:

Looks nice! Some nitpicks ;)

> Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.>

Missing "com" :)

> +/**
> + * enum mac80211_scan_flag - currently active scan mode
> + *
> + * @SCAN_SW_SCANNING: We're off our operating channel for scanning
> + * @SCAN_HW_SCANNING: The hardware is scanning for us, we have no way to
> + *	determine if we are on the operating channel or not
> + * @SCAN_BG_SCANNING: We're currently in the process of scanning but may
> + *	as well be on the operating channel
> + */
>  enum mac80211_scan_flag {
>  	SCAN_SW_SCANNING = 1,"SCAN_ENTER_OPER_CHANNEL"
>  	SCAN_HW_SCANNING = 2,
> +	SCAN_BG_SCANNING = 4,

There's some random stuff in there that doesn't belong. Also I would
prefer you used BIT(0) etc. or maybe __test_bit().

> --- a/net/mac80211/iface.c
> +++ b/net/mac80211/iface.c
> @@ -513,7 +513,7 @@ static int ieee80211_stop(struct net_device *dev)
>  			 * the scan_sdata is NULL already don't send out a
>  			 * scan event to userspace -- the scan is incomplete.
>  			 */
> -			if (local->scanning & SCAN_SW_SCANNING)
> +			if (local->scanning & SCAN_BG_SCANNING)
>  				ieee80211_scan_completed(&local->hw, true);
>  		}

That doesn't seem correct -- it should be kept I think.

> diff --git a/net/mac80211/main.c b/net/mac80211/main.c
> index a1b4887..a87522f 100644
> --- a/net/mac80211/main.c
> +++ b/net/mac80211/main.c
> @@ -198,7 +198,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
>  	}
>  
>  	if (changed & BSS_CHANGED_BEACON_ENABLED) {
> -		if (local->scanning & SCAN_SW_SCANNING) {
> +		if (local->scanning & SCAN_BG_SCANNING) {
>  			sdata->vif.bss_conf.enable_beacon = false;

That too.

> diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
> index 3df8a6e..24739ab 100644
> --- a/net/mac80211/rx.c
> +++ b/net/mac80211/rx.c
> @@ -2136,7 +2136,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
>  		return;
>  	}
>  
> -	if (unlikely(local->scanning))
> +	if (unlikely((local->scanning & SCAN_HW_SCANNING) || (local->scanning & SCAN_SW_SCANNING)))

I would prefer
	if (unlikely(local->scanning & (SCAN_HW_SCANNING | SCAN_SW_SCANNING)))

>  		rx.flags |= IEEE80211_RX_IN_SCAN;
>  
>  	ieee80211_parse_qos(&rx);
> diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
> index b4cc556..8f33fb5 100644
> --- a/net/mac80211/scan.c
> +++ b/net/mac80211/scan.c
> @@ -282,7 +282,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
>  		cfg80211_scan_done(local->scan_req, aborted);
>  	local->scan_req = NULL;
>  
> -	was_hw_scan = local->scanning & SCAN_HW_SCANNING;
> +	was_hw_scan = !!(local->scanning & SCAN_HW_SCANNING);

Should that be in the other patch?

> @@ -435,7 +434,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
>  	if (local->ops->hw_scan)
>  		local->scanning |= SCAN_HW_SCANNING;
>  	else
> -		local->scanning |= SCAN_SW_SCANNING;
> +		local->scanning |= SCAN_BG_SCANNING;

Ok now I'm confused. Did you really intend to replace all these?

Based on your initial description I thought it was going to be
	scanning == SW_SCANNING
or
	scanning == SW_SCANNING | BG_SCANNING

> +	if (local->scan_channel) {
> +		/*
> +		 * we're currently scanning a different channel, let's
> +		 * switch back to the operating channel now if at least
> +		 * one interface is associated. Otherwise just scan the
> +		 * next channel
> +		 */
> +		if (associated)
> +			local->scan_state = SCAN_ENTER_OPER_CHANNEL;
> +		else
> +			local->scan_state = SCAN_SET_CHANNEL;

:)
 
> +	/* advance to the next channel to be scanned */
> +	*next_delay = HZ / 10;
> +	local->scan_state = SCAN_SET_CHANNEL;

Maybe we should rename scan_state to next_scan_state.

> +	if (ieee80211_hw_config(local,
> +					IEEE80211_CONF_CHANGE_CHANNEL))

That looks weird. I don't think you really need to care about the return
value anyway, now that we have rfkill integrated it shouldn't ever be
nonzero (and if it is, while rfkill is being activated, it doesn't
really matter since we're taking down interfaces)

> +	/*
> +	 * notify the AP about us being back and restart all STA interfaces
> +	 */
> +	mutex_lock(&local->iflist_mtx);
> +	list_for_each_entry(sdata, &local->interfaces, list) {
> +		if (!netif_running(sdata->dev))
> +			continue;
> +
> +		/* Tell AP we're back */
> +		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
> +			if (sdata->u.mgd.associated) {
> +				ieee80211_scan_ps_disable(sdata);
> +			}

Could drop a set of {} here.

> @@ -657,7 +760,7 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
>  	 * queued -- mostly at suspend under RTNL.
>  	 */
>  	mutex_lock(&local->scan_mtx);
> -	swscan = !!(local->scanning & SCAN_SW_SCANNING);
> +	swscan = !!(local->scanning & SCAN_BG_SCANNING);

and another one -- please explain?

Anyway looks pretty good to me! How does it fare during ping -f or
something?

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* Re: [PATCH] wl12xx: loop off by one.
From: Kalle Valo @ 2009-07-16  9:23 UTC (permalink / raw)
  To: Roel Kluin; +Cc: linux-wireless, Andrew Morton
In-Reply-To: <4A524E91.9040400@gmail.com>

Roel Kluin <roel.kluin@gmail.com> writes:

> with `while (loop++ < INIT_LOOP)' `loop' reaches -1 after the loop.

Sorry, my brains are on vacation mode right now and I can't understand
how loop can reach -1. Here's the code:

    loop = 0;
    while (loop++ < INIT_LOOP) {
          ...
    }

    if (loop >= INIT_LOOP) {
       wl1251_error("timeout waiting for the hardware to "
                    "complete initialization");
       return -EIO;
    }

What am I missing?

Also the patch won't apply to wireless-testing because main.c is renamed
to wl1251_main.c.

-- 
Kalle Valo

^ permalink raw reply

* Re: [PATCH] wireless: remove print_mac uses
From: Kalle Valo @ 2009-07-16  9:12 UTC (permalink / raw)
  To: Johannes Berg; +Cc: John Linville, linux-wireless
In-Reply-To: <1247671301.10754.6.camel@johannes.local>

Johannes Berg <johannes@sipsolutions.net> writes:

> Use %pM instead, and also remove stray variables
> declared with DECLARE_MAC_BUF.

Thanks, I'm glad that we can ditch that ugly print_mac().

For the wl1251 part:

Acked-by: Kalle Valo <kalle.valo@nokia.com>

-- 
Kalle Valo

^ permalink raw reply

* Re: [PATCH v2] wireless: wl12xx, fix lock imbalance
From: Kalle Valo @ 2009-07-16  9:09 UTC (permalink / raw)
  To: Jiri Slaby; +Cc: linville, luciano.coelho, linux-wireless, linux-kernel
In-Reply-To: <1247603833-10862-1-git-send-email-jirislaby@gmail.com>

Jiri Slaby <jirislaby@gmail.com> writes:

> Add omitted mutex_unlock to one of wl12xx_op_start fail paths (when
> wl12xx_chip_wakeup fails).

Thanks for fixing this.

> [v2]
> Power off the device, because:
> \= cite from http://marc.info/?l=linux-kernel&m=124755028209880&w=2
> If the chip cannot be booted, why should it remain powered on?
> In some rare cases, the chip might fail to initialize, but can
> recover if powered off and on again, so turning it off at this
> point is the right thing to do. =/

Yes, I agree with this.

> Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
> ---
>  drivers/net/wireless/wl12xx/main.c |    2 +-

Unfortunately this won't apply to wireless-testing because main.c is
renamed to wl1251_main.c. Can you respin the patch or do you want me to
do it? I'm sending other wl12xx patches anyway and it's easy for me to
rebase this one at the same time.

-- 
Kalle Valo

^ permalink raw reply

* [RFC/RFT 5/5] mac80211: implement basic background scanning
From: Helmut Schaa @ 2009-07-16  9:09 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <200907161104.41975.helmut.schaa@gmail.com>

Introduce a new scan flag "SCAN_BG_SCANNING" which basically tells us
that we are currently scanning but may as well be on the operating channel
to RX/TX data whereas "SCAN_SW_SCANNING" tells us that we are currently
on a different channel for scanning. While "SCAN_BG_SCANNING" is set
during the whole scan "SCAN_SW_SCANNING" is set when leaving the operating
channel and unset when coming back.

Introduce two new scan states "SCAN_LEAVE_OPER_CHANNEL" and
"SCAN_ENTER_OPER_CHANNEL" which basically implement the functionality we
need to leave the operating channel (send a nullfunc to the AP and stop
the queues) and enter it again (send a nullfunc to the AP and start the
queues again).

Enhance the scan state "SCAN_DECISION" to switch back to the operating
channel after each scanned channel. In the future it sould be simple
to enhance the decision state to scan as much channels in a row as the
qos latency allows us.

Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.>

---
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index be880b5..15e8b4a 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -570,9 +570,40 @@ enum queue_stop_reason {
 	IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
 };
 
+/**
+ * enum mac80211_scan_flag - currently active scan mode
+ *
+ * @SCAN_SW_SCANNING: We're off our operating channel for scanning
+ * @SCAN_HW_SCANNING: The hardware is scanning for us, we have no way to
+ *	determine if we are on the operating channel or not
+ * @SCAN_BG_SCANNING: We're currently in the process of scanning but may
+ *	as well be on the operating channel
+ */
 enum mac80211_scan_flag {
 	SCAN_SW_SCANNING = 1,"SCAN_ENTER_OPER_CHANNEL"
 	SCAN_HW_SCANNING = 2,
+	SCAN_BG_SCANNING = 4,
+};
+
+/**
+ * enum mac80211_scan_state - scan state machine states
+ *
+ * @SCAN_DECISION: Main entry point to the scan state machine, this state
+ *	determines if we should keep on scanning or switch back to the
+ *	operating channel
+ * @SCAN_SET_CHANNEL: Set the next channel to be scanned
+ * @SCAN_SEND_PROBE: Send probe requests and wait for probe responses
+ * @SCAN_LEAVE_OPER_CHANNEL: Leave the operating channel, notify the AP
+ *	about us leaving the channel and stop all associated STA interfaces
+ * @SCAN_ENTER_OPER_CHANNEL: Enter the operating channel again, notify the
+ *	AP about us being back and restart all associated STA interfaces
+ */
+enum mac80211_scan_state {
+	SCAN_DECISION,
+	SCAN_SET_CHANNEL,
+	SCAN_SEND_PROBE,
+	SCAN_LEAVE_OPER_CHANNEL,
+	SCAN_ENTER_OPER_CHANNEL,
 };
 
 struct ieee80211_local {
@@ -683,7 +714,7 @@ struct ieee80211_local {
 	int scan_channel_idx;
 	int scan_ies_len;
 
-	enum { SCAN_DECISION, SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
+	enum mac80211_scan_state scan_state;
 	struct delayed_work scan_work;
 	struct ieee80211_sub_if_data *scan_sdata;
 	enum nl80211_channel_type oper_channel_type;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 2e514f2..634442c 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -513,7 +513,7 @@ static int ieee80211_stop(struct net_device *dev)
 			 * the scan_sdata is NULL already don't send out a
 			 * scan event to userspace -- the scan is incomplete.
 			 */
-			if (local->scanning & SCAN_SW_SCANNING)
+			if (local->scanning & SCAN_BG_SCANNING)
 				ieee80211_scan_completed(&local->hw, true);
 		}
 
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index a1b4887..a87522f 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -198,7 +198,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 	}
 
 	if (changed & BSS_CHANGED_BEACON_ENABLED) {
-		if (local->scanning & SCAN_SW_SCANNING) {
+		if (local->scanning & SCAN_BG_SCANNING) {
 			sdata->vif.bss_conf.enable_beacon = false;
 		} else {
 			/*
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 3df8a6e..24739ab 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2136,7 +2136,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 		return;
 	}
 
-	if (unlikely(local->scanning))
+	if (unlikely((local->scanning & SCAN_HW_SCANNING) || (local->scanning & SCAN_SW_SCANNING)))
 		rx.flags |= IEEE80211_RX_IN_SCAN;
 
 	ieee80211_parse_qos(&rx);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index b4cc556..8f33fb5 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -282,7 +282,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 		cfg80211_scan_done(local->scan_req, aborted);
 	local->scan_req = NULL;
 
-	was_hw_scan = local->scanning & SCAN_HW_SCANNING;
+	was_hw_scan = !!(local->scanning & SCAN_HW_SCANNING);
 	local->scanning = 0;
 	local->scan_channel = NULL;
 
@@ -365,12 +365,11 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
 			ieee80211_bss_info_change_notify(
 				sdata, BSS_CHANGED_BEACON_ENABLED);
 
-		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-			if (sdata->u.mgd.associated) {
-				netif_tx_stop_all_queues(sdata->dev);
-				ieee80211_scan_ps_enable(sdata);
-			}
-		} else
+		/*
+		 * only handle non-STA interfaces here, STA interfaces
+		 * are handled in the scan state machine
+		 */
+		if (sdata->vif.type != NL80211_IFTYPE_STATION)
 			netif_tx_stop_all_queues(sdata->dev);
 	}
 	mutex_unlock(&local->iflist_mtx);
@@ -435,7 +434,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 	if (local->ops->hw_scan)
 		local->scanning |= SCAN_HW_SCANNING;
 	else
-		local->scanning |= SCAN_SW_SCANNING;
+		local->scanning |= SCAN_BG_SCANNING;
 	/*
 	 * Kicking off the scan need not be protected,
 	 * only the scan variable stuff, since now
@@ -473,17 +472,115 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 
 static int ieee80211_scan_state_decision(struct ieee80211_local *local, unsigned long *next_delay)
 {
-	/* if no more bands/channels left, complete scan */
+	bool associated = false;
+	struct ieee80211_sub_if_data *sdata;
+
+	/* if no more bands/channels left, complete scan and advance to the idle state */
 	if (local->scan_channel_idx >= local->scan_req->n_channels) {
 		ieee80211_scan_completed(&local->hw, false);
 		return 1;
 	}
 
+	/* check if at least one STA interface is associated */
+	mutex_lock(&local->iflist_mtx);
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		if (!netif_running(sdata->dev))
+			continue;
+
+		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+			if (sdata->u.mgd.associated) {
+				associated = true;
+				break;
+			}
+		}
+	}
+	mutex_unlock(&local->iflist_mtx);
+
+	if (local->scan_channel) {
+		/*
+		 * we're currently scanning a different channel, let's
+		 * switch back to the operating channel now if at least
+		 * one interface is associated. Otherwise just scan the
+		 * next channel
+		 */
+		if (associated)
+			local->scan_state = SCAN_ENTER_OPER_CHANNEL;
+		else
+			local->scan_state = SCAN_SET_CHANNEL;
+	} else {
+		/*
+		 * we're on the operating channel currently, let's
+		 * leave that channel now to scan another one
+		 */
+		local->scan_state = SCAN_LEAVE_OPER_CHANNEL;
+	}
+
 	*next_delay = 0;
-	local->scan_state = SCAN_SET_CHANNEL;
 	return 0;
 }
 
+static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, unsigned long *next_delay)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	local->scanning |= SCAN_SW_SCANNING;
+
+	/*
+	 * notify the AP about us leaving the channel and stop all STA interfaces
+	 */
+	mutex_lock(&local->iflist_mtx);
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		if (!netif_running(sdata->dev))
+			continue;
+
+		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+			netif_tx_stop_all_queues(sdata->dev);
+			if (sdata->u.mgd.associated)
+				ieee80211_scan_ps_enable(sdata);
+		}
+	}
+	mutex_unlock(&local->iflist_mtx);
+
+	/* advance to the next channel to be scanned */
+	*next_delay = HZ / 10;
+	local->scan_state = SCAN_SET_CHANNEL;
+}
+
+static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local, unsigned long *next_delay)
+{
+	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+
+	/* switch back to the operating channel */
+	local->scan_channel = NULL;
+	if (ieee80211_hw_config(local,
+					IEEE80211_CONF_CHANGE_CHANNEL))
+		printk(KERN_DEBUG "%s: failed to restore operational "
+		"channel during scan\n", sdata->dev->name);
+
+	/*
+	 * notify the AP about us being back and restart all STA interfaces
+	 */
+	mutex_lock(&local->iflist_mtx);
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		if (!netif_running(sdata->dev))
+			continue;
+
+		/* Tell AP we're back */
+		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+			if (sdata->u.mgd.associated) {
+				ieee80211_scan_ps_disable(sdata);
+			}
+			netif_tx_wake_all_queues(sdata->dev);
+		}
+	}
+	mutex_unlock(&local->iflist_mtx);
+
+	local->scanning &= ~SCAN_SW_SCANNING;
+
+	*next_delay = HZ / 5;
+	local->scan_state = SCAN_DECISION;
+}
+
 static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, unsigned long *next_delay)
 {
 	int skip;
@@ -606,6 +703,12 @@ void ieee80211_scan_work(struct work_struct *work)
 		case SCAN_SEND_PROBE:
 			ieee80211_scan_state_send_probe(local, &next_delay);
 			break;
+		case SCAN_LEAVE_OPER_CHANNEL:
+			ieee80211_scan_state_leave_oper_channel(local, &next_delay);
+			break;
+		case SCAN_ENTER_OPER_CHANNEL:
+			ieee80211_scan_state_enter_oper_channel(local, &next_delay);
+			break;
 		}
 	} while (next_delay == 0);
 
@@ -657,7 +760,7 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
 	 * queued -- mostly at suspend under RTNL.
 	 */
 	mutex_lock(&local->scan_mtx);
-	swscan = !!(local->scanning & SCAN_SW_SCANNING);
+	swscan = !!(local->scanning & SCAN_BG_SCANNING);
 	mutex_unlock(&local->scan_mtx);
 
 	if (swscan)

^ permalink raw reply related

* [RFC/RFT 4/5] mac80211: Replace {sw,hw}_scanning variables with a bitfield
From: Helmut Schaa @ 2009-07-16  9:08 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <200907161104.41975.helmut.schaa@gmail.com>

Use a bitfield to store the current scan mode instead of two boolean
variables {sw,hw}_scanning. This patch does not introduce functional
changes.

Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>

---
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 8e22200..6e3cca6 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -742,7 +742,7 @@ static void ieee80211_ibss_work(struct work_struct *work)
 	if (!netif_running(sdata->dev))
 		return;
 
-	if (local->sw_scanning || local->hw_scanning)
+	if (local->scanning)
 		return;
 
 	if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_ADHOC))
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4166418..be880b5 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -570,6 +570,11 @@ enum queue_stop_reason {
 	IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
 };
 
+enum mac80211_scan_flag {
+	SCAN_SW_SCANNING = 1,
+	SCAN_HW_SCANNING = 2,
+};
+
 struct ieee80211_local {
 	/* embed the driver visible part.
 	 * don't cast (use the static inlines below), but we keep
@@ -668,7 +673,7 @@ struct ieee80211_local {
 
 	/* Scanning and BSS list */
 	struct mutex scan_mtx;
-	bool sw_scanning, hw_scanning;
+	unsigned long scanning;
 	struct cfg80211_ssid scan_ssid;
 	struct cfg80211_scan_request int_scan_req;
 	struct cfg80211_scan_request *scan_req;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index cadb0f6..2e514f2 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -513,7 +513,7 @@ static int ieee80211_stop(struct net_device *dev)
 			 * the scan_sdata is NULL already don't send out a
 			 * scan event to userspace -- the scan is incomplete.
 			 */
-			if (local->sw_scanning)
+			if (local->scanning & SCAN_SW_SCANNING)
 				ieee80211_scan_completed(&local->hw, true);
 		}
 
@@ -903,7 +903,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
 	struct ieee80211_sub_if_data *sdata;
 	int count = 0;
 
-	if (local->hw_scanning || local->sw_scanning)
+	if (local->scanning)
 		return ieee80211_idle_off(local, "scanning");
 
 	list_for_each_entry(sdata, &local->interfaces, list) {
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 3234f37..a1b4887 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -198,7 +198,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 	}
 
 	if (changed & BSS_CHANGED_BEACON_ENABLED) {
-		if (local->sw_scanning) {
+		if (local->scanning & SCAN_SW_SCANNING) {
 			sdata->vif.bss_conf.enable_beacon = false;
 		} else {
 			/*
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 8a97b14..9a38269 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -597,7 +597,7 @@ static void ieee80211_mesh_work(struct work_struct *work)
 	if (!netif_running(sdata->dev))
 		return;
 
-	if (local->sw_scanning || local->hw_scanning)
+	if (local->scanning)
 		return;
 
 	while ((skb = skb_dequeue(&ifmsh->skb_queue)))
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 18dad22..6d62ee9 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -581,7 +581,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	if (!ifmgd->associated)
 		return;
 
-	if (sdata->local->sw_scanning || sdata->local->hw_scanning)
+	if (sdata->local->scanning)
 		return;
 
 	/* Disregard subsequent beacons if we are already running a timer
@@ -639,7 +639,7 @@ static void ieee80211_enable_ps(struct ieee80211_local *local,
 	 * If we are scanning right now then the parameters will
 	 * take effect when scan finishes.
 	 */
-	if (local->hw_scanning || local->sw_scanning)
+	if (local->scanning)
 		return;
 
 	if (conf->dynamic_ps_timeout > 0 &&
@@ -2035,7 +2035,7 @@ static void ieee80211_sta_work(struct work_struct *work)
 	if (!netif_running(sdata->dev))
 		return;
 
-	if (local->sw_scanning || local->hw_scanning)
+	if (local->scanning)
 		return;
 
 	if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 66c797c..3df8a6e 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -418,10 +418,10 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
 	struct ieee80211_local *local = rx->local;
 	struct sk_buff *skb = rx->skb;
 
-	if (unlikely(local->hw_scanning))
+	if (unlikely(local->scanning & SCAN_HW_SCANNING))
 		return ieee80211_scan_rx(rx->sdata, skb);
 
-	if (unlikely(local->sw_scanning)) {
+	if (unlikely(local->scanning & SCAN_SW_SCANNING)) {
 		/* drop all the other packets during a software scan anyway */
 		if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED)
 			dev_kfree_skb(skb);
@@ -2136,7 +2136,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 		return;
 	}
 
-	if (unlikely(local->sw_scanning || local->hw_scanning))
+	if (unlikely(local->scanning))
 		rx.flags |= IEEE80211_RX_IN_SCAN;
 
 	ieee80211_parse_qos(&rx);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index ef9d86d..b4cc556 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -265,7 +265,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 
 	mutex_lock(&local->scan_mtx);
 
-	if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) {
+	if (WARN_ON(!local->scanning)) {
 		mutex_unlock(&local->scan_mtx);
 		return;
 	}
@@ -275,16 +275,15 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 		return;
 	}
 
-	if (local->hw_scanning)
+	if (local->scanning & SCAN_HW_SCANNING)
 		ieee80211_restore_scan_ies(local);
 
 	if (local->scan_req != &local->int_scan_req)
 		cfg80211_scan_done(local->scan_req, aborted);
 	local->scan_req = NULL;
 
-	was_hw_scan = local->hw_scanning;
-	local->hw_scanning = false;
-	local->sw_scanning = false;
+	was_hw_scan = local->scanning & SCAN_HW_SCANNING;
+	local->scanning = 0;
 	local->scan_channel = NULL;
 
 	/* we only have to protect scan_req and hw/sw scan */
@@ -434,9 +433,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 	}
 
 	if (local->ops->hw_scan)
-		local->hw_scanning = true;
+		local->scanning |= SCAN_HW_SCANNING;
 	else
-		local->sw_scanning = true;
+		local->scanning |= SCAN_SW_SCANNING;
 	/*
 	 * Kicking off the scan need not be protected,
 	 * only the scan variable stuff, since now
@@ -459,11 +458,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 	mutex_lock(&local->scan_mtx);
 
 	if (rc) {
-		if (local->ops->hw_scan) {
-			local->hw_scanning = false;
+		if (local->ops->hw_scan)
 			ieee80211_restore_scan_ies(local);
-		} else
-			local->sw_scanning = false;
+		local->scanning = 0;
 
 		ieee80211_recalc_idle(local);
 
@@ -569,7 +566,7 @@ void ieee80211_scan_work(struct work_struct *work)
 		return;
 	}
 
-	if (local->scan_req && !(local->sw_scanning || local->hw_scanning)) {
+	if (local->scan_req && !local->scanning) {
 		struct cfg80211_scan_request *req = local->scan_req;
 		int rc;
 
@@ -660,7 +657,7 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
 	 * queued -- mostly at suspend under RTNL.
 	 */
 	mutex_lock(&local->scan_mtx);
-	swscan = local->sw_scanning;
+	swscan = !!(local->scanning & SCAN_SW_SCANNING);
 	mutex_unlock(&local->scan_mtx);
 
 	if (swscan)
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 969a4b2..4f3d7f1 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -192,7 +192,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
 	if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
 		return TX_CONTINUE;
 
-	if (unlikely(tx->local->sw_scanning) &&
+	if (unlikely(tx->local->scanning & SCAN_SW_SCANNING) &&
 	    !ieee80211_is_probe_req(hdr->frame_control) &&
 	    !ieee80211_is_nullfunc(hdr->frame_control))
 		/*
@@ -1376,7 +1376,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 
 	if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
 	    local->hw.conf.dynamic_ps_timeout > 0 &&
-	    !local->sw_scanning && !local->hw_scanning && local->ps_sdata) {
+	    !(local->scanning) && local->ps_sdata) {
 		if (local->hw.conf.flags & IEEE80211_CONF_PS) {
 			ieee80211_stop_queues_by_reason(&local->hw,
 					IEEE80211_QUEUE_STOP_REASON_PS);

^ permalink raw reply related

* [RFC/RFT 3/5] mac80211: introduce a new scan state "decision"
From: Helmut Schaa @ 2009-07-16  9:08 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <200907161104.41975.helmut.schaa@gmail.com>

Introduce a new scan state "decision" which is entered after
every completed scan operation and decides about the next steps.
At first the decision is in any case to scan the next channel.
This shouldn't introduce any functional changes.

Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>

---
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 6a01771..4166418 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -678,7 +678,7 @@ struct ieee80211_local {
 	int scan_channel_idx;
 	int scan_ies_len;
 
-	enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
+	enum { SCAN_DECISION, SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
 	struct delayed_work scan_work;
 	struct ieee80211_sub_if_data *scan_sdata;
 	enum nl80211_channel_type oper_channel_type;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 60a4e00..ef9d86d 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -376,7 +376,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
 	}
 	mutex_unlock(&local->iflist_mtx);
 
-	local->scan_state = SCAN_SET_CHANNEL;
+	local->scan_state = SCAN_DECISION;
 	local->scan_channel_idx = 0;
 
 	spin_lock_bh(&local->filter_lock);
@@ -474,17 +474,25 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 	return rc;
 }
 
-static int ieee80211_scan_state_set_channel(struct ieee80211_local *local, unsigned long *next_delay)
+static int ieee80211_scan_state_decision(struct ieee80211_local *local, unsigned long *next_delay)
 {
-	int skip;
-	struct ieee80211_channel *chan;
-	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
-
 	/* if no more bands/channels left, complete scan */
 	if (local->scan_channel_idx >= local->scan_req->n_channels) {
 		ieee80211_scan_completed(&local->hw, false);
 		return 1;
 	}
+
+	*next_delay = 0;
+	local->scan_state = SCAN_SET_CHANNEL;
+	return 0;
+}
+
+static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, unsigned long *next_delay)
+{
+	int skip;
+	struct ieee80211_channel *chan;
+	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+
 	skip = 0;
 	chan = local->scan_req->channels[local->scan_channel_idx];
 
@@ -504,7 +512,7 @@ static int ieee80211_scan_state_set_channel(struct ieee80211_local *local, unsig
 	local->scan_channel_idx++;
 
 	if (skip)
-		return 0;
+		return;
 
 	/*
 	 * Probe delay is used to update the NAV, cf. 11.1.3.2.2
@@ -519,13 +527,13 @@ static int ieee80211_scan_state_set_channel(struct ieee80211_local *local, unsig
 	if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
 	    !local->scan_req->n_ssids) {
 		*next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
-		return 0;
+		local->scan_state = SCAN_DECISION;
+		return;
 	}
 
+	/* active scan, send probes */
 	*next_delay = IEEE80211_PROBE_DELAY;
 	local->scan_state = SCAN_SEND_PROBE;
-
-	return 0;
 }
 
 static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, unsigned long *next_delay)
@@ -545,7 +553,7 @@ void ieee80211_scan_state_send_probe(struct ieee80211_local *local, unsigned lon
 	 * on the channel.
 	 */
 	*next_delay = IEEE80211_CHANNEL_TIME;
-	local->scan_state = SCAN_SET_CHANNEL;
+	local->scan_state = SCAN_DECISION;
 }
 
 void ieee80211_scan_work(struct work_struct *work)
@@ -591,9 +599,12 @@ void ieee80211_scan_work(struct work_struct *work)
 	 */
 	do {
 		switch (local->scan_state) {
+	 	case SCAN_DECISION:
+	 		if (ieee80211_scan_state_decision(local, &next_delay))
+ 				return;
+ 			break;
 		case SCAN_SET_CHANNEL:
-			if (ieee80211_scan_state_set_channel(local, &next_delay))
-				return;
+			ieee80211_scan_state_set_channel(local, &next_delay);
 			break;
 		case SCAN_SEND_PROBE:
 			ieee80211_scan_state_send_probe(local, &next_delay);

^ permalink raw reply related

* [RFC/RFT 2/5] mac80211: advance the state machine immediately if no delay is needed
From: Helmut Schaa @ 2009-07-16  9:07 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <200907161104.41975.helmut.schaa@gmail.com>

Instead of queueing the scan work again without delay just process the
next state immediately.

Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>

---
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index a20f9e7..60a4e00 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -585,15 +585,21 @@ void ieee80211_scan_work(struct work_struct *work)
 		return;
 	}
 
-	switch (local->scan_state) {
-	case SCAN_SET_CHANNEL:
-		if (ieee80211_scan_state_set_channel(local, &next_delay))
-			return;
-		break;
-	case SCAN_SEND_PROBE:
-		ieee80211_scan_state_send_probe(local, &next_delay);
-		break;
-	}
+	/*
+	 * as long as no delay is required advance immediately
+	 * without scheduling a new work
+	 */
+	do {
+		switch (local->scan_state) {
+		case SCAN_SET_CHANNEL:
+			if (ieee80211_scan_state_set_channel(local, &next_delay))
+				return;
+			break;
+		case SCAN_SEND_PROBE:
+			ieee80211_scan_state_send_probe(local, &next_delay);
+			break;
+		}
+	} while (next_delay == 0);
 
 	queue_delayed_work(local->hw.workqueue, &local->scan_work,
 			   next_delay);

^ permalink raw reply related

* [RFC/RFT 1/5] mac80211: refactor the scan code
From: Helmut Schaa @ 2009-07-16  9:06 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <200907161104.41975.helmut.schaa@gmail.com>

Move the processing of each scan state into its own functions for better
readability. This patch does not introduce functional changes.

Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>

---
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 7482065..a20f9e7 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -474,13 +474,85 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 	return rc;
 }
 
+static int ieee80211_scan_state_set_channel(struct ieee80211_local *local, unsigned long *next_delay)
+{
+	int skip;
+	struct ieee80211_channel *chan;
+	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+
+	/* if no more bands/channels left, complete scan */
+	if (local->scan_channel_idx >= local->scan_req->n_channels) {
+		ieee80211_scan_completed(&local->hw, false);
+		return 1;
+	}
+	skip = 0;
+	chan = local->scan_req->channels[local->scan_channel_idx];
+
+	if (chan->flags & IEEE80211_CHAN_DISABLED ||
+	    (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
+	     chan->flags & IEEE80211_CHAN_NO_IBSS))
+		skip = 1;
+
+	if (!skip) {
+		local->scan_channel = chan;
+		if (ieee80211_hw_config(local,
+					IEEE80211_CONF_CHANGE_CHANNEL))
+			skip = 1;
+	}
+
+	/* advance state machine to next channel/band */
+	local->scan_channel_idx++;
+
+	if (skip)
+		return 0;
+
+	/*
+	 * Probe delay is used to update the NAV, cf. 11.1.3.2.2
+	 * (which unfortunately doesn't say _why_ step a) is done,
+	 * but it waits for the probe delay or until a frame is
+	 * received - and the received frame would update the NAV).
+	 * For now, we do not support waiting until a frame is
+	 * received.
+	 *
+	 * In any case, it is not necessary for a passive scan.
+	 */
+	if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
+	    !local->scan_req->n_ssids) {
+		*next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+		return 0;
+	}
+
+	*next_delay = IEEE80211_PROBE_DELAY;
+	local->scan_state = SCAN_SEND_PROBE;
+
+	return 0;
+}
+
+static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, unsigned long *next_delay)
+{
+	int i;
+	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+
+	for (i = 0; i < local->scan_req->n_ssids; i++)
+		ieee80211_send_probe_req(
+			sdata, NULL,
+			local->scan_req->ssids[i].ssid,
+			local->scan_req->ssids[i].ssid_len,
+			local->scan_req->ie, local->scan_req->ie_len);
+
+	/*
+	 * After sending probe requests, wait for probe responses
+	 * on the channel.
+	 */
+	*next_delay = IEEE80211_CHANNEL_TIME;
+	local->scan_state = SCAN_SET_CHANNEL;
+}
+
 void ieee80211_scan_work(struct work_struct *work)
 {
 	struct ieee80211_local *local =
 		container_of(work, struct ieee80211_local, scan_work.work);
 	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
-	struct ieee80211_channel *chan;
-	int skip, i;
 	unsigned long next_delay = 0;
 
 	mutex_lock(&local->scan_mtx);
@@ -515,65 +587,11 @@ void ieee80211_scan_work(struct work_struct *work)
 
 	switch (local->scan_state) {
 	case SCAN_SET_CHANNEL:
-		/* if no more bands/channels left, complete scan */
-		if (local->scan_channel_idx >= local->scan_req->n_channels) {
-			ieee80211_scan_completed(&local->hw, false);
+		if (ieee80211_scan_state_set_channel(local, &next_delay))
 			return;
-		}
-		skip = 0;
-		chan = local->scan_req->channels[local->scan_channel_idx];
-
-		if (chan->flags & IEEE80211_CHAN_DISABLED ||
-		    (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
-		     chan->flags & IEEE80211_CHAN_NO_IBSS))
-			skip = 1;
-
-		if (!skip) {
-			local->scan_channel = chan;
-			if (ieee80211_hw_config(local,
-						IEEE80211_CONF_CHANGE_CHANNEL))
-				skip = 1;
-		}
-
-		/* advance state machine to next channel/band */
-		local->scan_channel_idx++;
-
-		if (skip)
-			break;
-
-		/*
-		 * Probe delay is used to update the NAV, cf. 11.1.3.2.2
-		 * (which unfortunately doesn't say _why_ step a) is done,
-		 * but it waits for the probe delay or until a frame is
-		 * received - and the received frame would update the NAV).
-		 * For now, we do not support waiting until a frame is
-		 * received.
-		 *
-		 * In any case, it is not necessary for a passive scan.
-		 */
-		if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
-		    !local->scan_req->n_ssids) {
-			next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
-			break;
-		}
-
-		next_delay = IEEE80211_PROBE_DELAY;
-		local->scan_state = SCAN_SEND_PROBE;
 		break;
 	case SCAN_SEND_PROBE:
-		for (i = 0; i < local->scan_req->n_ssids; i++)
-			ieee80211_send_probe_req(
-				sdata, NULL,
-				local->scan_req->ssids[i].ssid,
-				local->scan_req->ssids[i].ssid_len,
-				local->scan_req->ie, local->scan_req->ie_len);
-
-		/*
-		 * After sending probe requests, wait for probe responses
-		 * on the channel.
-		 */
-		next_delay = IEEE80211_CHANNEL_TIME;
-		local->scan_state = SCAN_SET_CHANNEL;
+		ieee80211_scan_state_send_probe(local, &next_delay);
 		break;
 	}
 

^ permalink raw reply related

* [PATCH 3/8] b43: Use %pM conversion specifier
From: Tobias Klauser @ 2009-07-16  8:56 UTC (permalink / raw)
  To: stefano.brivio, mb, linville, johannes, linux-wireless, netdev
  Cc: Tobias Klauser

Use the %pM conversion specifier for printk instead of print_mac.

Signed-off-by: Tobias Klauser <klto@zhaw.ch>
---
 drivers/net/wireless/b43/main.c |    4 +---
 1 files changed, 1 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index e71c8d9..3f4360a 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -938,7 +938,6 @@ static void b43_clear_keys(struct b43_wldev *dev)
 static void b43_dump_keymemory(struct b43_wldev *dev)
 {
 	unsigned int i, index, offset;
-	DECLARE_MAC_BUF(macbuf);
 	u8 mac[ETH_ALEN];
 	u16 algo;
 	u32 rcmta0;
@@ -973,8 +972,7 @@ static void b43_dump_keymemory(struct b43_wldev *dev)
 						((index - 4) * 2) + 1);
 			*((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
 			*((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
-			printk("   MAC: %s",
-			       print_mac(macbuf, mac));
+			printk("   MAC: %pM", mac);
 		} else
 			printk("   DEFAULT KEY");
 		printk("\n");
-- 
1.6.0.4


^ permalink raw reply related

* [RFC/RFT 0/5] mac80211: implement background scan
From: Helmut Schaa @ 2009-07-16  9:04 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

Hi,

this patch series implements basic background scanning in mac80211
by interrupting the scan after each scanned channel to allow RX/TX.

I only tested the patches on current wireless-testing with iwlagn
in sw-scan mode and it works fine already. One thing I noticed but
seems to be unrelated is: in sw-scan mode the connection sometimes
stalls and no data is transferred anymore although the connection is
still available and I found no way to recover it without setting
it up again.

So, it would be great if somebody could test the patches on other
hardware as well.

Thanks a lot,
Helmut

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox