From 80e78ef74dffb2195e2a1164c18579180a76fd5b Mon Sep 17 00:00:00 2001
From: Dan Williams <dcbw@redhat.com>
Date: Fri, 25 May 2007 22:18:47 -0400
Subject: [PATCH] libertas: fix deadlock SIOCGIWSCAN handler

Update signal quality before the locked scan result translation loop,
because calling libertas_prepare_and_send_command() with the
'waitforrsp' option grabs adapter->lock in the command return processing,
leading to the deadlock.

Signed-off-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
 drivers/net/wireless/libertas/scan.c | 35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)

(limited to 'drivers/net')

diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index abc9d56..8aaac5f 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -1506,7 +1506,6 @@ static inline char *libertas_translate_scan(wlan_private *priv,
 	char *current_val;	/* For rates */
 	struct iw_event iwe;	/* Temporary buffer */
 	int j;
-	int ret;
 #define PERFECT_RSSI ((u8)50)
 #define WORST_RSSI   ((u8)0)
 #define RSSI_DIFF    ((u8)(PERFECT_RSSI - WORST_RSSI))
@@ -1560,22 +1559,18 @@ static inline char *libertas_translate_scan(wlan_private *priv,
 		iwe.u.qual.noise =
 		    CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
 	}
-	if ((adapter->mode == IW_MODE_AUTO) &&
-	    !libertas_SSID_cmp(&adapter->curbssparams.ssid, &bss->ssid)
-	    && adapter->adhoccreate) {
-		ret = libertas_prepare_and_send_command(priv,
-					    cmd_802_11_rssi,
-					    0,
-					    cmd_option_waitforrsp,
-					    0, NULL);
-
-		if (!ret) {
-			iwe.u.qual.level =
-			    CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] /
-				     AVG_SCALE,
-				     adapter->NF[TYPE_RXPD][TYPE_AVG] /
-				     AVG_SCALE);
-		}
+
+	/* Locally created ad-hoc BSSs won't have beacons if this is the
+	 * only station in the adhoc network; so get signal strength
+	 * from receive statistics.
+	 */
+	if ((adapter->mode == IW_MODE_ADHOC)
+	    && adapter->adhoccreate
+	    && !libertas_SSID_cmp(&adapter->curbssparams.ssid, &bss->ssid)) {
+		int snr, nf;
+		snr = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+		nf = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+		iwe.u.qual.level = CAL_RSSI(snr, nf);
 	}
 	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
 
@@ -1665,6 +1660,12 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
 	if (!adapter->nr_cmd_pending && adapter->last_scanned_channel)
 		wlan_scan_networks(priv, NULL, 0);
 
+	/* Update RSSI if current BSS is a locally created ad-hoc BSS */
+	if ((adapter->inframode == wlan802_11ibss) && adapter->adhoccreate) {
+		libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
+					cmd_option_waitforrsp, 0, NULL);
+	}
+
 	mutex_lock(&adapter->lock);
 	list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) {
 		char * next_ev;
-- 
cgit v1.1