All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ben Greear <greearb@candelatech.com>
To: "linux-wireless@vger.kernel.org" <linux-wireless@vger.kernel.org>
Subject: RFC:  mac80211/ath9k:  allow scanning single channel if other VIF is associated.
Date: Mon, 13 Sep 2010 16:14:05 -0700	[thread overview]
Message-ID: <4C8EB03D.7070808@candelatech.com> (raw)

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

This patch aims to decrease channel switching when there is at least one
interface associated.  This should help multiple station interfaces co-exist
on the same hardware, especially in WPA mode.

This patch is on top of the other 3 I posted recently, and even though I think
this patch is going in the right direction, I still cannot get two WPA interfaces
to complete authentication.

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


[-- Attachment #2: scan_one.patch --]
[-- Type: text/plain, Size: 9600 bytes --]

diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 1165f90..13673bb 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1605,7 +1605,12 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 		struct ieee80211_channel *curchan = hw->conf.channel;
 		int pos = curchan->hw_value;
 
+		/* If channels are the same, then don't actually do anything.
+		 */
+		if (sc->sc_ah->curchan == &sc->sc_ah->channels[pos])
+			goto skip_chan_change;
+		
 		aphy->chan_idx = pos;
 		aphy->chan_is_ht = conf_is_ht(conf);
 		if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4e635e2..631b094 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -790,6 +790,8 @@ struct ieee80211_local {
 	enum ieee80211_band hw_scan_band;
 	int scan_channel_idx;
 	int scan_ies_len;
+	int scanned_count; /* how many channels scanned so far in this scan */
+	bool scan_probe_once; /* if true, scan only the current channel. */
 
 	unsigned long leave_oper_channel_time;
 	enum mac80211_scan_state next_scan_state;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0cb822c..abb76ae 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1845,10 +1845,11 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
 
 		else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-			printk(KERN_DEBUG "No probe response from AP %pM"
-				" after %dms, try %d\n", bssid,
+			printk(KERN_DEBUG "%s: No probe response from AP %pM"
+				" after %dms, try %d  flags: 0x%x\n",
+				sdata->dev->name, bssid,
 				(1000 * IEEE80211_PROBE_WAIT)/HZ,
-				ifmgd->probe_send_count);
+				ifmgd->probe_send_count, ifmgd->flags);
 #endif
 			ieee80211_mgd_probe_ap_send(sdata);
 		} else {
@@ -1858,9 +1859,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
 			 */
 			ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
 					  IEEE80211_STA_BEACON_POLL);
-			printk(KERN_DEBUG "No probe response from AP %pM"
-				" after %dms, disconnecting.\n",
-				bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
+			printk(KERN_DEBUG "%s: No probe response from AP %pM"
+			       " after %dms, disconnecting, flags: 0x%x\n",
+			       sdata->dev->name, bssid,
+			       (1000 * IEEE80211_PROBE_WAIT)/HZ, ifmgd->flags);
 			ieee80211_set_disassoc(sdata, true);
 			mutex_unlock(&ifmgd->mtx);
 			mutex_lock(&local->mtx);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index ac205a3..e8ea84d 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2399,7 +2399,7 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
 	do {				\
 		res = rxh(rx);		\
 		if (res != RX_CONTINUE)	\
-			goto rxh_next;  \
+			goto rxh_next;	\
 	} while (0);
 
 	while ((skb = __skb_dequeue(frames))) {
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index e20fb52..1c9f0a8 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -292,7 +292,9 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 	/* we only have to protect scan_req and hw/sw scan */
 	mutex_unlock(&local->mtx);
 
-	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+	if (!local->scan_probe_once)
+		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+
 	if (was_hw_scan)
 		goto done;
 
@@ -300,7 +302,8 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 
 	drv_sw_scan_complete(local);
 
-	ieee80211_offchannel_return(local, true);
+	if (!local->scan_probe_once)
+		ieee80211_offchannel_return(local, true);
 
  done:
 	mutex_lock(&local->mtx);
@@ -340,13 +343,43 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
 	 * nullfunc frames and probe requests will be dropped in
 	 * ieee80211_tx_h_check_assoc().
 	 */
-	drv_sw_scan_start(local);
+	int avifs = 0;
+	int svifs = 0;
+	struct ieee80211_sub_if_data *sdata;
+
+	mutex_lock(&local->iflist_mtx);
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		if (!ieee80211_sdata_running(sdata))
+			continue;
 
-	ieee80211_offchannel_stop_beaconing(local);
+		if (sdata->vif.type != NL80211_IFTYPE_STATION
+		    || sdata->u.mgd.associated)
+			avifs++;
 
-	local->leave_oper_channel_time = 0;
+		if (sdata->vif.type == NL80211_IFTYPE_STATION)
+			svifs++;
+	}
+	mutex_unlock(&local->iflist_mtx);
+
+	/* If one sta is associated, we don't want another to start scanning,
+	 * as that will un-associate the first.
+	 * TODO:  This still leaves a race when a thundering herd of WPA
+	 * supplicants are all coming up at once.
+	 */
+	if ((avifs > 1) || ((avifs == 1) && (svifs > 1)))
+		local->scan_probe_once = true;
+	else
+		local->scan_probe_once = false;
+
+	drv_sw_scan_start(local);
+
+	if (!local->scan_probe_once) {
+		ieee80211_offchannel_stop_beaconing(local);
+		local->leave_oper_channel_time = 0;
+		local->scan_channel_idx = 0;
+	}
+	local->scanned_count = 0;
 	local->next_scan_state = SCAN_DECISION;
-	local->scan_channel_idx = 0;
 
 	drv_flush(local, false);
 
@@ -459,7 +492,8 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
 	struct ieee80211_channel *next_chan;
 
 	/* if no more bands/channels left, complete scan and advance to the idle state */
-	if (local->scan_channel_idx >= local->scan_req->n_channels) {
+	if ((local->scan_channel_idx >= local->scan_req->n_channels) ||
+	    (local->scanned_count && local->scan_probe_once)) {
 		__ieee80211_scan_completed(&local->hw, false);
 		return 1;
 	}
@@ -528,10 +562,13 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
 			local->next_scan_state = SCAN_SET_CHANNEL;
 	} else {
 		/*
-		 * we're on the operating channel currently, let's
-		 * leave that channel now to scan another one
+		 * we're on the operating channel currently, Leave that
+		 * channel if we are not probing the single channel.
 		 */
-		local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
+		if (local->scan_probe_once)
+			local->next_scan_state = SCAN_SET_CHANNEL;
+		else
+			local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
 	}
 
 	*next_delay = 0;
@@ -566,14 +603,15 @@ static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *loca
 {
 	/* switch back to the operating channel */
 	local->scan_channel = NULL;
-	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
-
-	/*
-	 * Only re-enable station mode interface now; beaconing will be
-	 * re-enabled once the full scan has been completed.
-	 */
-	ieee80211_offchannel_return(local, false);
+	if (!local->scan_probe_once) {
+		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 
+		/*
+		 * Only re-enable station mode interface now; beaconing will be
+		 * re-enabled once the full scan has been completed.
+		 */
+		ieee80211_offchannel_return(local, false);
+	}
 	__clear_bit(SCAN_OFF_CHANNEL, &local->scanning);
 
 	*next_delay = HZ / 5;
@@ -587,19 +625,25 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
 	struct ieee80211_channel *chan;
 
 	skip = 0;
-	chan = local->scan_req->channels[local->scan_channel_idx];
+	if (local->scan_probe_once) {
+		chan = local->oper_channel;
+		local->scan_channel = chan;
+	} else {
+		chan = local->scan_req->channels[local->scan_channel_idx];
+		local->scan_channel = chan;
 
-	local->scan_channel = chan;
-	if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
-		skip = 1;
+		if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
+			skip = 1;
 
-	/* advance state machine to next channel/band */
-	local->scan_channel_idx++;
+		/* advance state machine to next channel/band */
+		local->scan_channel_idx++;
 
-	if (skip) {
-		/* if we skip this channel return to the decision state */
-		local->next_scan_state = SCAN_DECISION;
-		return;
+		if (skip) {
+			/* if we skip this channel return to the decision
+			 * state */
+			local->next_scan_state = SCAN_DECISION;
+			return;
+		}
 	}
 
 	/*
@@ -615,6 +659,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
 	if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
 	    !local->scan_req->n_ssids) {
 		*next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+		local->scanned_count++;
 		local->next_scan_state = SCAN_DECISION;
 		return;
 	}
@@ -637,6 +682,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
 			local->scan_req->ssids[i].ssid_len,
 			local->scan_req->ie, local->scan_req->ie_len);
 
+	local->scanned_count++;
 	/*
 	 * After sending probe requests, wait for probe responses
 	 * on the channel.
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index ae344d1..1bfc1e0 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -910,12 +910,17 @@ static void ieee80211_work_work(struct work_struct *work)
 			 *	 happen to be on the same channel as
 			 *	 the requested channel
 			 */
-			ieee80211_offchannel_stop_beaconing(local);
-			ieee80211_offchannel_stop_station(local);
-
-			local->tmp_channel = wk->chan;
-			local->tmp_channel_type = wk->chan_type;
-			ieee80211_hw_config(local, 0);
+			if (!(wk->chan == local->scan_channel ||
+			      (wk->chan == local->oper_channel &&
+			       !local->scan_channel))) {
+				/* Only change channels if we need to */
+				ieee80211_offchannel_stop_beaconing(local);
+				ieee80211_offchannel_stop_station(local);
+
+				local->tmp_channel = wk->chan;
+				local->tmp_channel_type = wk->chan_type;
+				ieee80211_hw_config(local, 0);
+			}
 			started = true;
 			wk->timeout = jiffies;
 		}

             reply	other threads:[~2010-09-13 23:14 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-09-13 23:14 Ben Greear [this message]
2010-09-15  3:03 ` RFC: mac80211/ath9k: allow scanning single channel if other VIF is associated Jouni Malinen
2010-09-15  5:30   ` Ben Greear
2010-09-15  5:46     ` Dan Williams
2010-09-15  5:48       ` Dan Williams
2010-09-15  5:49       ` Ben Greear
2010-09-15 10:16     ` Johannes Berg
2010-09-15 14:21       ` Ben Greear
2010-09-15 14:24         ` Johannes Berg
2010-09-15 15:32           ` Ben Greear
2010-09-15 15:37             ` Johannes Berg
2010-09-15 16:12               ` Ben Greear
2010-09-15 20:31     ` Jouni Malinen
2010-09-15 21:04       ` Luis R. Rodriguez
2010-09-16  0:11         ` Ben Greear

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4C8EB03D.7070808@candelatech.com \
    --to=greearb@candelatech.com \
    --cc=linux-wireless@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.